如何在fileupload struts2中删除.tmp文件

我在strtus-2.3.15.3使用了file-upload (common fileuplod)。 我的.jsp有一个Form有多个字段,有很多diff类型(textfield,textarea,hidden,file),包括FILE和明显的SUBMIT

当我通过选择一个文件提交表单并在所有其他字段中输入一些文本时,它会在提到临时文件夹中生成.tmp文件。 将文件上传到myfolder后,只有与文件字段相关的.tmp文件才会被删除,但其余的.tmp (1kb大小)文件正在作为其保留。

 List items = upload.parseRequest(servletRequest); 

下面代码中的这一行为所有具有一定值的字段生成.tmp文件(如果未在文本字段中输入任何文本,则不生成)。

MonitoredMultiPartRequest.java

 public void parse(HttpServletRequest servletRequest, String saveDir) throws IOException { System.setProperty("java.io.tmpdir", "D:\\ankit"); UploadListener listener = new UploadListener(servletRequest); // Create a factory for disk-based file items FileItemFactory factory = new MonitoredDiskFileItemFactory(listener); // Create a new file upload handler ServletFileUpload upload = new ServletFileUpload(factory); } 

MonitoredDiskFileItemFactory

 public class MonitoredDiskFileItemFactory extends DiskFileItemFactory { HttpServletRequest request; public MonitoredDiskFileItemFactory(OutputStreamListener listener, HttpServletRequest request) { this.listener = null; this.listener = listener; this.request = request; setTrackers(); } public void setTrackers() { FileCleaningTracker fileCleaningTracker = FileCleanerCleanup.getFileCleaningTracker(request.getServletContext()); File repository = new File(System.getProperty("java.io.tmpdir")); DiskFileItemFactory factory = new DiskFileItemFactory(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD, repository); factory.setFileCleaningTracker(fileCleaningTracker); super.setFileCleaningTracker(fileCleaningTracker); super.setRepository(repository); } public MonitoredDiskFileItemFactory(int sizeThreshold, File repository, OutputStreamListener listener) { super(sizeThreshold, repository); this.listener = null; this.listener = listener; } public FileItem createItem(String fieldName, String contentType, boolean isFormField, String fileName) { MonitoredDiskFileItem result = new MonitoredDiskFileItem(fieldName, contentType, isFormField, fileName, getSizeThreshold(), getRepository(), listener); FileCleaningTracker tracker = getFileCleaningTracker(); if (tracker != null) { tracker.track(result.getTempFileOfDistFileItem(), result); } return result; } private OutputStreamListener listener; } 

MonitoredDiskFileItem

 public class MonitoredDiskFileItem extends DiskFileItem { public MonitoredDiskFileItem(String fieldName, String contentType, boolean isFormField, String fileName, int sizeThreshold, File repository, OutputStreamListener listener) { super(fieldName, contentType, isFormField, fileName, sizeThreshold, repository); mos = null; this.listener = listener; } public OutputStream getOutputStream() throws IOException { if (mos == null) mos = new MonitoredOutputStream(super.getOutputStream(), listener); return mos; } public File getTempFileOfDistFileItem() { return super.getTempFile(); } private MonitoredOutputStream mos; private OutputStreamListener listener; } 

UploadListener

 public class UploadListener implements OutputStreamListener, Serializable { private static final long serialVersionUID = 1L; private int totalToRead = 0; private int totalBytesRead = 0; private int percentDone = 0; private int previou_percentDone = 0; private long uploadspeed = 0; private long starttime; private long stTime, EndTime; HttpSession session; private int count = 0; public UploadListener(HttpServletRequest request) { totalToRead = request.getContentLength(); session = request.getSession(); } public void start() { session.setAttribute("percentageDone", 0); session.setAttribute("speed", 0); starttime = System.currentTimeMillis(); stTime = starttime; } public String getMessage() { return "" + totalBytesRead + " bytes have been read (" + percentDone + "% done) "; } public void bytesRead(int bytesRead) { totalBytesRead = totalBytesRead + bytesRead; if (100.00 * totalBytesRead > totalToRead) { previou_percentDone = percentDone; percentDone = (int) Math.round(100.00 * totalBytesRead / totalToRead); if (previou_percentDone  0) speed = Math.round(((totalBytesRead) / TimediffInSecond) / 1048576); else speed = totalBytesRead / 1048576; } catch (Exception e) { System.err.println(e.getMessage()); } } } } public void done() { EndTime = System.currentTimeMillis(); session.setAttribute("percentageDone", 100); session.setAttribute("speed", 100); } @Override public void error(String message) { // System.out.println(message); } public long getUploadspeed() { return uploadspeed; } public void setUploadspeed(long uploadspeed) { this.uploadspeed = uploadspeed; } } 

EDIT

1>为什么为字段(textarea,hidden,textfield)生成此.tmp文件。 我们怎么能防止这种情况?

2>我想停止为所有字段生成.tmp文件,除了type='file' (文件字段)。

3>否则,如何删除所有.tmp文件?

你不需要Commons库,也不需要Servlet。

您正在使用Struts2,因此不要重新发明轮子并使用动作拦截器

您可以在这个详尽的答案中找到使用Struts2上传多个文件的代码,并通过在另一个答案中创建自定义对象来进行一些改进。

在通过Servlet讨论fileUpload时,我觉得有必要将BalusC的这个好答案联系起来。


让我们来讨论您的具体问题:您正在使用MonitoredDiskFileItemFactory (您没有指定在Web上增长的许多实现中的哪一个,但很可能是 – >)标准org.apache.commons.fileupload.disk.DiskFileItemFactory的子类org.apache.commons.fileupload.disk.DiskFileItemFactory

在JavaDoc中,很好地解释了:

此实现创建了FileItem实例,这些实例将其内容保留在内存中 ,较小的项目或磁盘上的临时文件中 ,以用于较大的项目。 内容将存储在磁盘上的大小阈值是可配置的 ,就像创建临时文件的目录一样。

如果未另行配置,则默认配置值如下:

  • 大小阈值为10KB。
  • 存储库是系统默认临时目录,由System.getProperty("java.io.tmpdir")

注意:文件是在系统默认临时目录中创建的,具有可预测的名称。 这意味着对该目录具有写访问权限的本地攻击者可以执行TOUTOC攻击,以使用攻击者选择的文件替换任何上载的文件。 这意味着将取决于上载文件的使用方式,但可能很重要。 在具有本地不受信任的用户的环境中使用此实现时,必须使用setRepository(File)来配置不可公开写入的存储库位置。 在Servlet容器中,可以使用ServletContext属性javax.servlet.context.tempdir标识的位置。

应为以后删除为文件项创建的临时文件。 执行此操作的最佳方法是使用FileCleaningTracker ,您可以在DiskFileItemFactory上设置DiskFileItemFactory 但是,如果您使用此类跟踪器,则必须考虑以下事项:临时文件会在不再需要时自动删除。 (更准确地说,当相应的File实例被垃圾收集时。)这是由所谓的reaper线程完成的,它在加载类FileCleaner时自动启动。 终止该线程可能是有意义的,例如,如果您的Web应用程序结束。 请参阅commons-fileupload用户指南中的“资源清理”部分。

来自Commons FileUpload Documantation

资源清理

如果您使用的是DiskFileItem ,则本节仅适用。 换句话说,如果您上传的文件在处理之前写入临时文件,则适用。

如果不再使用这些临时文件,则会自动删除这些临时文件(更准确地说,如果相应的java.io.File实例是垃圾收集的。这是由org.apache.commons.io.FileCleaner类默默完成的,它启动收割者的线程。

如果不再需要,则应停止此收割者线程。 在servlet环境中,这是通过使用名为FileCleanerCleanup的特殊servlet上下文侦听器来FileCleanerCleanup 。 为此,请在web.xml中添加如下部分:

  ...   org.apache.commons.fileupload.servlet.FileCleanerCleanup   ...  

创建DiskFileItemFactory

FileCleanerCleanup提供了org.apache.commons.io.FileCleaningTracker的实例。 创建org.apache.commons.fileupload.disk.DiskFileItemFactory时必须使用此实例。 这应该通过调用如下方法来完成:

 public static DiskFileItemFactory newDiskFileItemFactory(ServletContext context , File repository) { FileCleaningTracker fileCleaningTracker = FileCleanerCleanup.getFileCleaningTracker(context); DiskFileItemFactory factory = new DiskFileItemFactory(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD, repository); factory.setFileCleaningTracker(fileCleaningTracker); return factory; } 

禁用清除临时文件

要禁用对临时文件的跟踪,可以将FileCleaningTracker设置为null。 因此,将不再跟踪创建的文件。 特别是,它们将不再自动删除。

然后你可以:

  1. 设置更高的threeshold,将所有内容保存在内存中,而不是使用临时文件,或
  2. 遵循Apache准则,在不再需要临时文件正确擦除它们。