我正在为我的网络应用程序开发上传图片功能,并且我遇到了来自apache commons fileupload的“FileCleaningTracker”的奇怪问题。我有一个带有实例变量FileCleaningTracker的ImageUploadService,然后我有一个创建DiskFileItemFactory实例然后引用FileCleaningTracker的上传方法,在upload方法成功完成后,我将DiskFileItemFactory的FileCleaningTracker设置为null,所以我希望DiskFileItemFactory要进行垃圾回收,然后会通知FileCleaningTracker中PhantomReference的基础子类,因此删除DiskFileItemFactory创建的临时文件。
但是直到我将DiskFileItemFactory归零并且在upload方法结束时调用System.gc()(仅使DiskFileItemFactory无效)时才会发生这种情况。这对我来说似乎很奇怪。这是我的代码:
@Override
public void upload(final HttpServletRequest request) {
ValidateUtils.checkNotNull(request, "upload request");
final File tmp = new File(this.tempFolder);
if (!tmp.exists()) {
tmp.mkdir();
}
DiskFileItemFactory fileItemFactory = new DiskFileItemFactory(this.sizeThreshold, tmp);
fileItemFactory.setFileCleaningTracker(this.fileCleaningTracker);
ServletFileUpload uploadHandler = new ServletFileUpload(fileItemFactory);
List items;
try {
items = uploadHandler.parseRequest(request);
} catch (final FileUploadException e) {
throw new ImageUploadServiceException("Error parsing the http servlet request for image upload.", e);
}
final Iterator it = items.iterator();
while (it.hasNext()) {
final DiskFileItem item = (DiskFileItem) it.next();
if (item.isFormField()) {
// log message
} else {
final String fileName = item.getName();
final File destination = this.createFileForUpload(fileName, this.uploadFolder);
FileChannel outChannel;
try {
outChannel = new FileOutputStream(destination).getChannel();
} catch (final FileNotFoundException e) {
throw new ImageUploadServiceException(e);
}
FileChannel inChannel = null;
try {
inChannel = new FileInputStream(item.getStoreLocation()).getChannel();
outChannel.transferFrom(inChannel, 0, item.getSize());
} catch (final IOException e) {
throw new ImageUploadServiceException(String.format("Error uploading image to '%s/%s'.", this.uploadFolder, destination.getName()), e);
} finally {
IOUtils.closeChannel(inChannel);
IOUtils.closeChannel(outChannel);
}
}
}
fileItemFactory.setFileCleaningTracker(null);
}
上面的代码导致每次上传都在temp文件夹中创建一个文件,但最后却没有通过“fileCleaningTracker”删除它,可能是因为DiskFileItemFactory实例没有被垃圾收集(我没看清为什么它应该'或者已经GCed但没有通过fileCleaningTracker中的PhantomReference通知(PhantomReference有多可靠?)
我等了10分钟,文件仍在那里,所以不应该因为GC没有运行。并且没有例外。
现在,如果我添加以下代码,则每次上传后都会删除临时文件:
fileItemFactory = null;
System.gc();
这对我来说非常奇怪,因为我希望fileItemFactory可以在没有对System.gc()的明确调用的情况下进行GC。
任何意见都将受到赞赏。
谢谢。
答案 0 :(得分:6)
我有同样的问题。即使在服务器关闭后,也永远不会删除临时文件:GC进程尚未启动,因此FileCleaningTracker
无法从ReferenceQueue
获取要删除的跟踪文件,并且所有文件都保留在硬盘驱动器上。< / p>
由于我的应用程序的特定行为,我必须在每次上传后清理(文件可能非常大)。而不是使用标准org.apache.commons.io.FileCleaningTracker
我很幸运能够用我自己的实现来覆盖这个类:
/**
* Cleaning tracker to clean files after each upload with special method invocation.
* Not thread safe and must be used with 1 factory = 1 thread policy.
*/
public class DeleteFilesOnEndUploadCleaningTracker extends FileCleaningTracker {
private List<String> filesToDelete = new ArrayList();
public void deleteTemporaryFiles() {
for (String file : filesToDelete) {
new File(file).delete();
}
filesToDelete.clear();
}
@Override
public synchronized void exitWhenFinished() {
deleteTemporaryFiles();
}
@Override
public int getTrackCount() {
return filesToDelete.size();
}
@Override
public void track(File file, Object marker) {
filesToDelete.add(file.getAbsolutePath());
}
@Override
public void track(File file, Object marker, FileDeleteStrategy deleteStrategy) {
filesToDelete.add(file.getAbsolutePath());
}
@Override
public void track(String path, Object marker) {
filesToDelete.add(path);
}
@Override
public void track(String path, Object marker, FileDeleteStrategy deleteStrategy) {
filesToDelete.add(path);
}
}
如果这是正确的情况,只需将上述类的实例注入DiskFileItemFactory
:
DeleteFilesOnEndUploadCleaningTracker tracker = new DeleteFilesOnEndUploadCleaningTracker();
fileItemFactory.setFileCleaningTracker(tracker);
在完成上传项目的工作后,不要忘记调用清理方法:
tracker.deleteTemporaryFiles();
忘记提及:我使用commons-fileupload
版本1.2.2和commons-io
版本1.3.2。