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

时间:2013-10-23 13:44:25

标签: java tomcat file-upload struts2 temporary-files

我在file-upload中使用过strtus-2.3.15.3(常见文件副本)。 我的.jsp中有一个表单,其中多个字段包含许多差异类型(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 < percentDone)
            {
                long speed = 0;
                try
                {
                    double TimediffInSecond = (System.currentTimeMillis() - starttime) / 1000;
                    if (TimediffInSecond > 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&GT;为什么为字段(textarea,hidden,textfield)生成此.tmp文件。 我们怎么能防止这种情况?

2 - ;我想停止为除.tmp(文件字段)之外的所有字段生成type='file'文件。

3&GT;否则,如何删除所有.tmp文件?

1 个答案:

答案 0 :(得分:4)

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

您正在使用Struts2,因此请勿重新发明轮子并使用操作拦截器

您可以找到upload multiple files with Struts2 in this exhaustive answer的代码,creating a custom object in this other answer稍微改进一下。

在通过Servlet讨论fileUpload时,我觉得还需要链接this nice answer from BalusC


让我们来讨论您的具体问题:您正在使用MonitoredDiskFileItemFactory,(您没有指定在网络上发展的众多实施中的哪一个,但很可能是 - &gt;)标准org.apache.commons.fileupload.disk.DiskFileItemFactory的子类。

在JavaDoc中,很好地解释了:

  

此实现会创建FileItem个实例来保留它们   内容,较小的项目,或临时文件中的内容   磁盘,适用于较大的商品。 大小阈值,高于该阈值内容   存储在磁盘上,可配置,其中的目录也是如此   将创建临时文件。

     

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

     
      
  • 尺寸阈值为10KB。
  •   
  • Repository是系统默认的临时目录,由返回   System.getProperty("java.io.tmpdir")
  •   
     

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

     

应删除为文件项创建的临时文件   稍后的。最好的方法是使用FileCleaningTracker,   您可以在DiskFileItemFactory上设置。但是,如果你使用   这样的跟踪器,那么你必须考虑以下内容:临时文件   一旦不再需要,它们就会自动删除。 (更多   确切地说,当File的相应实例是垃圾时   收集。)这是通过所谓的收割者线程来完成的   加载类FileCleaner时自动启动。它可能   有意义的是终止该线程,例如,如果你的网络   申请结束。请参阅用户中的“资源清理”部分   commons-fileupload指南。

来自Commons FileUpload Documantation

  

资源清理

     

如果您使用的是DiskFileItem,则此部分仅适用。其他   如果您上传的文件是临时的,则适用   处理它们之前的文件。

     

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

     

如果不再需要这个收割者线程,应该停止它。在一个   servlet环境,这是通过使用特殊的servlet上下文完成的   监听器,称为FileCleanerCleanup。为此,请添加类似的部分   跟随你的web.xml:

<web-app>
  ...
  <listener>
    <listener-class>
      org.apache.commons.fileupload.servlet.FileCleanerCleanup
    </listener-class>
  </listener>
  ...
</web-app>
     

创建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为空。因此,创建的文件将不会   更长的跟踪。特别是,它们将不再被删除   自动。

然后你可以:

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