Java文件上传组件,Fastupload 0.31 功能完备速度飙升

openkk 12年前
   <p><a href="/misc/goto?guid=4958347258558211177" target="_blank">fastupload </a>0.31版本上周已经发布,因为工作的关系,只到今天才有点时间来写一些0.31版本中深层次的东西。fastupload以前的版本,尽管在性能上取得 了不小的进步,但只支持解析文件,不支持解析非文件的内容,因为HttpFileUploadParser这个类来解析ServletRequest的输 入流的过程中,忽略非文件的请求数据。举个列子来说,假如表单中有两个input标签,一个是文本输入控件,一个是文件输入控件,经过 HttpFileUploadParser解析后,只会把文件类型请求的数据保存在指定的目录下。</p>    <p>在fastupload项目编写之初,考虑的是如何把文件类型请求的数据保存到文件中去,在这种目标下,如何处理非文件类型请求数据?自然的”选择“了忽略这种方式。</p>    <p>在fastupload 0.23发布后 ,原计划是在下一个版本中提供对struts2、spring mvc3的注解(annotation)一些高级特性的支持,有些网友对fastupload提出了批评和建议,其中,网友<strong>silence1214</strong> 提出了对于非文件类型请求数据的处理问题。经过仔细考虑后,决定先实现非文件类型请求数据的处理。于是,0.31版本中,类HttpMemoryUploadParser能处理非文件类型的请求数据了,具体的示例代码如下,</p>    <pre class="brush:java; toolbar: true; auto-links: false;">MultiPartDataFactory mpdf = new MemoryMultiPartDataFactory("utf-8");    HttpMemoryUploadParser uploadParser = new HttpMemoryUploadParser(request, mpdf);    long s = System.currentTimeMillis();    List<MultiPartData> list = uploadParser.parseList();      File dir = new File(System.getProperty("user.home") + "/memoryupload/dump");    dir.mkdirs();      for (MultiPartData e : list) {     String target = String.format("%s/%s", dir.getAbsolutePath(), e.getFileName());     if (e.isFile()) {     e.toFile(target);     }     else {      System.out.println(new String(e.getContentBuffer()));     }    }      System.out.format("memoryupload cost: %d %n", System.currentTimeMillis() - s);</pre>    <p> </p>    <p>当新建一个HttpMemoryUploadParser类的实例时,首先读取ServletRequest输入流中所有的字节,写入内存缓冲中,parseList()函数从这片大的缓冲中解析上传表单中的内容,返回一个包含MultiPartData类型的数组。</p>    <p> </p>    <p>这里的MultiPartData是multipart/form-data中两个边界(boundary)中数据的一个抽象。上传请求数据中的头 部信息表明这部分数据是一个文件中的内容,还是输入控件中“输入”的内容,MultiPartData.isFile()函数则实现了这个判断功能,此 外,MultiPartData.getContentHeaderMap()函数把这些“头部信息”以Map的形式暴露出来,供外部代码使用。</p>    <p>在成功解析上传表单后,每个MultiPartData都有一个自己的一片内存缓冲,用于保存解析后所得出的数据,如果需要把这些数据保存到文件中 去,则调用toFile()函数,如果想直接获得数据,则调用getContentBuffer()函数。需要提醒的是,创建 MemoryMultiPartDataFactory时,指定了字符集,MemoryMultiPartDataFactory在创建 MemoryMultiPartData对象时,对把name属性转换成所指定的字符集字符串,对于所解析出的内容,并不做字符集的转换,因为数据已经读 入到内存中,开发人员可以对其转换成所期望的字符集,不象MultiPartTextFile写入时,需要强制进行字符集转换。</p>    <p>对于支持非文件类型请求后,fastupload和Apache Commons FileUpload的性能相比,是一个什么样的结果呢?继续做一个实际的测试对比,分别用fastupload的 HttpMemoryUploadParser和Apache Commons FileUpload的相类似的API接受1.7M、1.7M和1.2M的图像文件。得到下面的测试结果,单位毫秒。</p>    <pre class="java">memoryupload cost: 10   memoryupload cost: 8   memoryupload cost: 11   memoryupload cost: 8   memoryupload cost: 12   memoryupload cost: 8   memoryupload cost: 48   memoryupload cost: 14   memoryupload cost: 346   memoryupload cost: 11   memoryupload cost: 8   memoryupload cost: 9   memoryupload cost: 14   memoryupload cost: 8   memoryupload cost: 14   memoryupload cost: 9   memoryupload cost: 10   memoryupload cost: 14   memoryupload cost: 10   memoryupload cost: 12   Apache Common File Upload costs: 379   Apache Common File Upload costs: 29   Apache Common File Upload costs: 66   Apache Common File Upload costs: 87   Apache Common File Upload costs: 92   Apache Common File Upload costs: 24   Apache Common File Upload costs: 195   Apache Common File Upload costs: 286   Apache Common File Upload costs: 25   Apache Common File Upload costs: 314   Apache Common File Upload costs: 50   Apache Common File Upload costs: 84   Apache Common File Upload costs: 217   Apache Common File Upload costs: 86   Apache Common File Upload costs: 314   Apache Common File Upload costs: 120 </pre>    <p>可以看出,两组数据中,最快的单次时间比是8:24,如果比较两组数据中前10个的平均值,这个比是8.8:51,如果比较最慢的10个数据的平均值,是49.6:229, 最慢的单次比值是 346:379,相差不大,平均时间比是29.2:140。</p>    <p>总的说来,得益于改进的BM查找算法,HttpMemoryUploadParser解析速度比Apache Commons FileUpload的要快好很多,速度上占据了绝对的优势,从最慢那个对比来看,fastupload仍然有提高的空间,比如说尽可能的优化内存的使 用。</p>    <p>开源fastupload项目纯粹我当时的一个想法,没想到引起了广大网友的注意,不屑、质疑、建议、批评的都有,不管怎么说,你们的声音是fastupload项目前进中动力的重要部分,这里特别感谢广大网友。</p>