Apache FileUpload详细介绍

Apache FileUpload组件
在最初的 http 协议中,没有上传文件方面的功能。RFC1867("Form-based File Upload in HTML".)为 http 协议添加了这个功能。客户端的浏览器,如 Microsoft IE, Mozila, Opera 等,按照此规范将用户指定的文件发送到服务器。服务器端的网页程序,如 php, asp, jsp 等,可以按照此规范,解析出用户发送来的文件。

1.1、客户端
简单来说,RFC1867规范要求http协议增加了file类型的input标签,用于浏览需要上传的文件。同时要求FORM表单的enctype属性设置为“multipart/form-data”,method属性设置为“post”即可,下面是我们文。
件上传页面的表单代码:
<form action="<%=request.getContextPath()%>/Upload3Servlet" 
 method="post" 
 enctype="multipart/form-data">
File1:<input type="file" name="file"/><br/>
Desc:<input type="text" name="desc"/><br/>
<input type="submit" value="提交"/>
</form>

1.2、服务器端
一个文件上传请求的消息实体由一系列根据 RFC1867("Form-based File Upload in HTML".)编码的项目(文本参数和文件参数)组成。自己编程来解析获取这些数据是非常麻烦的,还需要了解RFC1867规范对请求数据编码的相关知识。FileUpload 可以帮助我们解析这样的请求,将每一个项目封装成一个实现了FileItem接口的对象,并以列表的形式返回。所以,我们只需要了解FileUpload的API如何使用即可,不用管它们的底层实现。
让我们来看一个简单文件上传处理代码:
package cn.itcast.servlet;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
/**
 * 文件上传
 * @author <a href="mailto:wj@itcast.cn">王健</a>
 */
public class UploadServlet extends HttpServlet {
@SuppressWarnings("unchecked")
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
DiskFileItemFactory f = new DiskFileItemFactory();//磁盘对象
f.setRepository(new File("d:/a")); //设置临时目录
f.setSizeThreshold(1024*8); //8k的缓冲区,文件大于8K则保存到临时目录
ServletFileUpload upload = new ServletFileUpload(f);//声明解析request的对象
upload.setHeaderEncoding("UTF-8"); //处理文件名中文
upload.setFileSizeMax(1024 * 1024 * 5);// 设置每个文件最大为5M
upload.setSizeMax(1024 * 1024 * 10);// 一共最多能上传10M
String path = getServletContext().getRealPath("/imgs");//获取文件要保存的目录
try {
List<FileItem> list = upload.parseRequest(request);// 解析
for (FileItem ff : list) {
if (ff.isFormField()) {
String ds = ff.getString("UTF-8");//处理中文
System.err.println("说明是:" + ds);
} else {
String ss = ff.getName();
ss = ss.substring(ss.lastIndexOf("\\") + 1);//解析文件名
FileUtils.copyInputStreamToFile( //直接使用commons.io.FileUtils
ff.getInputStream(),
new File(path + "/" + ss));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}




1.6、FileItemStream性能提升
以下是使用FileItemStream三次上传一个70M文件的时间:
文件名为:电影.avi
Desc:这是信息
用时:1516
文件名为:电影.avi
Desc:这是信息
用时:703
文件名为:电影.avi
Desc:这是信息
用时:656
对比:
以下是用FileItem三次上传一个70M文件的时间:
文件名为:电影.avi
说明是:这是信息
用时:1687
文件名为:电影.avi
说明是:这是信息
用时:2578
文件名为:电影.avi
说明是:这是信息
用时:2297
可见:FileItemSteam(servletFileUpload.getItemIterator(httpServletRequest))速度要快于FileItem(servletFileUpload.parseRequest(request))速度。且一般情况下,FileItemSteam不产生临时文件:
源代码:
package cn.itcast.servlet;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Scanner;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
/**
 * FileItemStream示例
 * @author <a href="mailto:wj@itcast.cn">王健</a>
 * @version 1.0 2012-3-15
 */
public class Upload3Servlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long start = System.currentTimeMillis();
String path = getServletContext().getRealPath("/imgs");
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(1024 * 8);// 设置8k的缓存空间
factory.setRepository(new File("d:/a"));
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("UTF-8");// 设置文件名处理中文编码
try {
FileItemIterator fii = upload.getItemIterator(request);// 使用遍历类
while (fii.hasNext()) {
FileItemStream fis = fii.next();
if (fis.isFormField()) {//FileItemStream同样使用OpenStream获取普通表单的值
InputStreamReader in = new InputStreamReader(fis.openStream(),"UTF-8");
Scanner sc = new Scanner(in);
StringBuffer sb = new StringBuffer();
if(sc.hasNextLine()){
sb.append(sc.nextLine());
}
System.err.println("Desc:"+sb.toString());
} else {
String fileName = fis.getName();
fileName = fileName
.substring(fileName.lastIndexOf("\\") + 1);
System.err.println("文件名为:" + fileName);
InputStream in = fis.openStream();
FileUtils.copyInputStreamToFile(in, new File(path+"/"+fileName));
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.err.println("用时:"+(end-start));
}
}



1.7、FileCleanerCleanup清理资源 
    只适用于你使用 DiskFileItem 的情况.换句话说,就是在你处理上传的数据之前它们被存放在临时文件中。
    这些临时文件在不再被使用的时候(如果相应的java.io.File是可回收的则更好)会自动被删除.这会被org.apache.commons.io.FileCleaningTracker的一个实例启动的一个收割线程默默执行。
    你的web应用应该使用org.apache.commons.fileupload.FileCleanerCleanup的一个实例.那很简单,你只要把它加到你的 web.xml 中:
  <listener>
  <listener-class>org.apache.commons.fileupload.servlet.FileCleanerCleanup</listener-class>
  </listener>
然后,在创建了DiskFileItemFactory以后,设置资源回收:
DiskFileItemFactory f = new DiskFileItemFactory();//声明临时文件对象
f.setFileCleaningTracker(FileCleanerCleanup.getFileCleaningTracker(this.getServletContext()));
f.setSizeThreshold(1024*8); //设置在内存中最多可以放多少个字节,如果超出这个字节,保存到临文件中去
f.setRepository(new File("d:/a")); //设置临时目录

注意:必须要正常关闭Tomcat服务器。因为此线程在tomcat终止时会调用清空临时文件的代码。
正常关闭,是指执行CATALINA_HOME\bin\shutdown.bat文件。


1.8、进度ProgressListener
这个进度条比较合适于在后台监控进度,如果在作上传进度,还是使用ajax更加合适:
示例代码:
upload.setProgressListener(new ProgressListener() {
double dd = 0;
long len = 0;
//参数1:已经上传完成的数量
//参数2:总长度
//参数3:第几个元素从1开始。0为没有
public void update(long pBytesRead, long pContentLength, int pItems) {
double persent = pBytesRead*100/pContentLength;
if(dd!=persent){
System.err.println(dd+"%");
dd=persent;
}else if(persent==100){
System.err.println("100%");
}
}
});

摘自----http://www.open-open.com/lib/view/open1338108871261.html
参考 ----http://zhangjunhd.blog.51cto.com/113473/18331/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值