• commons-fileupload源码学习心得


    commons-fileupload依赖于commons-io包。

    commons-fileupload的使用方法:

      1.创建一个文件项目工厂类DiskFileItemFactory。

            DiskFileItemFactory有俩个构造方法:

    1 DiskFileItemFactory() 其中sizeThreshold是默认值10kB, 文件大小不超过这个值将内容保存在内存,超过这个值会把文件保存到临时目录下,可用System.getProperty("java.io.tmpdir")获取;
    2 DiskFileItemFactory(int sizeThreshold, File repository)  可以指定sizeThreshold, 和文件保存到磁盘的路径。

            DiskFileItemFactory有一个属性FileCleaningTracker,设置这个属性可以用来追踪删除临时文件。当这个临时文件不再被使用时将会被立即删除,更精确的说是这个文件对象被垃圾收集器回收时,FileCleaningTracker将启动收获者线程(reaper thread)自动删除这个临时文件。FileCleaningTracker是commons-io包的工具类。  

    1 FileCleaningTracker fileCleaningTracker = FileCleanerCleanup.getFileCleaningTracker(servletcontext);
    2 DiskFileItemFactory factory = new DiskFileItemFactory();
    3 factory.setFileCleaningTracker(fileCleaningTracker);  
    4 ServletContext获取的几种方法:
    5     Javax.servlet.http.HttpSession.getServletContext();
    6     Javax.servlet.jsp.PageContext.getServletContext();
    7     Javax.servlet.ServletConfig.getServletContext();

      2.创建一个文件处理类ServletFileUpload。

        ServletFileUpload解析上传请求request的信息,封装到FileItem类中,我们通过FileItem可以获取文件的名称、大小、文件流等信息。

    1 ServletFileUpload sfu = new ServletFileUpload(factory);
    2   ServletFileUpload可以设置:
    3     headerEncoding 读取请求头信息时使用的编码
    4     sizeMax 单次请求所能上传的文件总大小的最大size,默认是-1,不限制大小
    5     fileSizeMax 单次请求所能上传的单个文件最大size,默认是-1,不限制大小
    6 List<FileItem> items = sfu.parseRequest(req);

     

    ServletFileUpload对上传请求信息的解析流程:

      文件上传的html代码如下:

    1 <form action="http://server.dom/cgi/handle" enctype="multipart/form-data" method=POST>
    2   What is your name? <input type=text name=submitter/>
    3   What files are you sending? <input type=file name=pics/>
    4 </form>

        浏览器传送的数据格式如下:

     1    Content-type: multipart/form-data, boundary=AaB03x
     2 
     3   --AaB03x
     4 
     5   content-disposition: form-data; name="field1"
     6 
     7   Joe Blow
     8 
     9   --AaB03x
    10 
    11   content-disposition: form-data; name="pics"; filename="file1.txt"
    12 
    13   Content-Type: text/plain
    14 
    15   ... contents of file1.txt ...
    16 
    17   --AaB03x--

       数据的每段格式如下:

     1      multipart-body := preamble 1*encapsulation close-delimiter epilogue
     2     encapsulation := delimiter body CRLF
     3      delimiter := "--" boundary CRLF
     4      close-delimiter := "--" boundary "--"
     5      preamble := &lt;ignore&gt;
     6      epilogue := &lt;ignore&gt;
     7      body := header-part CRLF body-part
     8      header-part := 1*header CRLF
     9      header := header-name ":" header-value
    10      header-name := &lt;printable ascii characters except ":"&gt;
    11      header-value := &lt;any ascii characters except CR & LF&gt;
    12      body-data := &lt;arbitrary data&gt;

      先通过request获取content-type,解析content-type获取每段的边界分隔字符串boundary。

      然后根据boundary获取header-part的header参数的值和body-data的值组装到FileItem中。

    FileCleaningTracker的使用方法:

        在web.xml配置如下监听器:

    1 <listener>
    2       <listener-class>org.apache.commons.fileupload.servlet.FileCleanerCleanup</listener-class>
    3 </listener>

     FileCleanerCleanup实现了ServletContextListener监听类,在web启动时调用ServletContext.setAttribute()方法设置了一个全局共享的FileCleaningTracker对象。

     在 Servlet API 中有一个 ServletContextListener 接口,它能够监听 ServletContext 对象的生命周期,实际上就是监听Web应用的生命周期。

       当Servlet 容器启动或终止Web 应用时,会触发ServletContextEvent 事件,该事件由 ServletContextListener 来处理。在 ServletContextListener 接口中定义了处理 ServletContextEvent 事件的两个方法:public void contextInitialized(ServletContextEvent sce)和public void contextDestroyed(ServletContextEvent sce)。

     ServletFileUpload在解析request,封装FileItem时,会将创建的临时文件添加到FileCleaningTracker的追踪容器trackers(一个Vector的集合)里,然后后台一直默默执行的收获者线程Reaper Thread会自动删除这个临时文件。

     Tracker类继承了PhantomReference虚引用,虚引用在系统垃圾回收器开始回收对象时 , 将直接调用 finalize() 方法 , 但不会立即将其加入回收队列 . 只有在真正对象被 GC 清除时 , 才会将其加入 Reference 队列中去。

     问题是:我没弄明白这个Reaper Thread多久会执行一次?什么条件会触发它?是否是在垃圾回收的时候才触发,哪位高手指点一二,多谢!!!

     Reaper线程的定义如下:

     1     /**
     2      * The reaper thread.
     3      */
     4     private final class Reaper extends Thread {
     5         /** Construct a new Reaper */
     6         Reaper() {
     7             super("File Reaper");
     8             setPriority(Thread.MAX_PRIORITY);
     9             setDaemon(true);
    10         }
    11 
    12         /**
    13          * Run the reaper thread that will delete files as their associated
    14          * marker objects are reclaimed by the garbage collector.
    15          */
    16         public void run() {
    17             // thread exits when exitWhenFinished is true and there are no more tracked objects
    18             while (exitWhenFinished == false || trackers.size() > 0) {
    19                 Tracker tracker = null;
    20                 try {
    21                     // Wait for a tracker to remove.
    22                     tracker = (Tracker) q.remove();
    23                 } catch (Exception e) {
    24                     continue;
    25                 }
    26                 if (tracker != null) {
    27                     tracker.delete();
    28                     tracker.clear();  //此处的作用不是很明白??
    29                     trackers.remove(tracker);  //此处明明移除了已删除的临时文件,但是我调用getTrackCount()方法查看等待删除的临时文件的个数没变,为什么呢?
    30                 }
    31             }
    32         }
    33     }

      

  • 相关阅读:
    Spring boot MultipartResolver
    shell 脚本中的当前工作目录等于执行脚本时所在的工作目录
    IDEA Exception in thread "main" java.lang.ClassNotFoundException: com.streamax.servicecore.business.FileManageServApplication
    java学习路线图-----java基础学习路线图(J2SE学习路线图)
    Java基本语法-----java数组(一维数组二维数组)
    Java基本语法-----java二维数组
    Java基本语法-----java函数
    程序员的自我修养-----Java开发的必须知道的几个注意点
    JAVA面向对象-----java面向对象的六大原则
    Java集合-----java集合框架常见问题
  • 原文地址:https://www.cnblogs.com/mihu/p/3793139.html
Copyright © 2020-2023  润新知