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 := <ignore> 6 epilogue := <ignore> 7 body := header-part CRLF body-part 8 header-part := 1*header CRLF 9 header := header-name ":" header-value 10 header-name := <printable ascii characters except ":"> 11 header-value := <any ascii characters except CR & LF> 12 body-data := <arbitrary data>
先通过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 }