【问题标题】:How to delete .tmp file in fileupload struts2如何在fileupload struts2中删除.tmp文件
【发布时间】:2013-11-01 19:57:40
【问题描述】:

我在strtus-2.3.15.3 中使用了file-upload(通用文件上传)。 我的.jsp 中有一个表单,其中包含多个字段,其中包含许多差异类型(文本字段、文本区域、隐藏、文件),包括 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> 为什么会为字段 (textarea ,hidden,textfield) 生成此 .tmp 文件。 我们怎样才能防止这种情况发生?

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

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

【问题讨论】:

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


    【解决方案1】:

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

    您正在使用 Struts2,所以不要重新发明轮子并使用 ActionsInterceptors

    你可以找到upload multiple files with Struts2 in this exhaustive answer的代码,creating a custom object in this other answer有一点改进。

    在谈到通过 Servlet 上传文件时,我觉得也需要链接 this nice answer from BalusC


    让我们来回答您的具体问题:您使用的是MonitoredDiskFileItemFactory,(您没有指定网络上增长的众多实现中的哪一个,但很可能是 -> ) 标准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 类,启动一个收割线程。

    如果不再需要这个 reaper 线程,应该停止它。在一个 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. 设置更高的三分之二,将所有内容保存在内存中,而不是使用临时文件,或者
    2. 当不再需要临时文件时,遵循 Apache 指南正确擦除临时文件

    【讨论】:

    • @Andrea . 感谢回复,我已经在我的应用程序中实现了这个,现在我不想改变整个流程(我重新发明了这个拦截器,因为我想跟踪每次上传的文件数量进度条)。
    • 我的问题是为什么这个.tmp 文件是为textarea 等其他字段生成的(有一些值),我怎样才能防止它生成.tmp 文件。 (如果我接受您的建议,而不是在同一问题发生后,会导致它在“解析 servletrequest”期间生成)
    • 你好你能帮忙我如何以及何时可以调用newDiskFileItemFactory()方法
    • 如果我们增加ThresholdSize会发生什么?它会降低性能吗?哪个最好创建 .tmp 文件或保留在内存中(根据性能)?
    • 如果增加ThresholdSize,您将需要更多的内存和更少的硬盘空间。它不会降低性能(它会提高性能,因为 RAM 比 HD 快,但可能以一种不明显的方式......)。哪个最好取决于您的需求:您要填充 RAM 还是 HD?
    猜你喜欢
    • 1970-01-01
    • 2018-02-04
    • 1970-01-01
    • 2019-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-06
    相关资源
    最近更新 更多