一) 基础简介:
1、FileUpload 是 Apache commons下面的一个子项目,用来实现Java环境下面的
文件上传功能,与常见的SmartUpload齐名。
2、组件FileUpload依赖于Commons IO组件。 目前FileUpload的最新版本是1.2.2 ,对于此版本官方推荐的依赖的IO组件版本是1.3.2
3、FileUpload 是基于RFC1867协议实现的。
4、API:
http://commons.apache.org/fileupload/apidocs/index.html
二)RFC1867协议:
RFC1867协议作为HTTP协议的附加协议,详细描述了File Upload的规则。RFC1867协议主要是在HTTP协议的基础上为INPUT标签增加了file属性,同时限定了Form的method必须为POST,ENCTYPE必须为multipart/form-data,当然还增加了一些与此相关属性。
比如value属性表示默认的上传文件的文件名(无文件上传时生效)
width表示默认的显示文件名的长度
height表示显示上传文件的个数
例子:
<FORM ACTION="http://server.dom/cgi/handle" ENCTYPE="multipart/form-data" METHOD=POST>
What is your name? <INPUT TYPE=TEXT NAME=field1>
What files are you sending? <INPUT TYPE=FILE NAME=pics>
</FORM>
假设用户在name一栏里输入"Joe Blow",上传了一个文件名叫"file1.txt"的文件。那么浏览器将发送的包格式会是这样:
Content-type:
multipart/form-data, boundary=AaB03x
--AaB03x
content-disposition: form-data; name="field1"
Joe Blow
--AaB03x
content-disposition: form-data;
name="pics"; filename="file1.txt"
Content-Type: text/plain
... contents of file1.txt ...
--AaB03x--
如果上传的文件中还包含一个叫"file2.gif"的图片,那么包格式将会是这样:
Content-type: multipart/form-data, boundary=AaB03x
--AaB03x
content-disposition: form-data; name="field1"
Joe Blow
--AaB03x
content-disposition: form-data; name="pics"
Content-type: multipart/mixed, boundary=BbC04y
--BbC04y
Content-disposition: attachment; filename="file1.txt"
Content-Type: text/plain
... contents of file1.txt ...
--BbC04y
Content-disposition: attachment; filename="file2.gif"
Content-type: image/gif
Content-Transfer-Encoding: binary
...contents of file2.gif...
--BbC04y--
--AaB03x--
总结:
RFC1867对HTTP头作了适当地变更,但变更很小。首先content-type头由以前的:
content-type: application/x-www-form-urlencoded
变为
content-type: multipart/form-data; +空格+ boundary=AaB03x
即增加了boundary,所谓的boundary其实就是分割线,RFC1867利用boundary分割HTTP实体数据。boundary中数字字符区是随机生成的。
三)代码样例:
最简单的一个例子:
// Create a factory for disk-based file items
FileItemFactory factory = new DiskFileItemFactory();
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);
// Parse the request
List <FileItem> items = upload.parseRequest(request);
如上我们就把request的所有信息包括上传文件的信息都转换到items这个对象里去了。
再增加一点点控制:
// Create a factory for disk-based file items
DiskFileItemFactory factory = new DiskFileItemFactory();
// Sets the size threshold beyond which files are written directly to disk.
factory.setSizeThreshold(yourMaxMemorySize);
// Sets the directory used to temporarily store files that are larger than the configured size threshold.
factory.setRepository(yourTempDirectory);
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);
// Sets the maximum allowed size of a complete request
upload.setSizeMax(yourMaxRequestSize);
// Parse the request
List <FileItem> items = upload.parseRequest(request);
FileItem的处理:
Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (item.isFormField()) { // Process a regular form field
String name = item.getFieldName();
String value = item.getString();
} else { // Process a file upload
String fieldName = item.getFieldName();
String fileName = item.getName();
String contentType = item.getContentType();
boolean isInMemory = item.isInMemory();
long sizeInBytes = item.getSize();
}
}
这里有必要对FileItem的一些方法做进一步的介绍:
public boolean isFormField() -- 用于判断 FileItem 类对象封装的数据是否属于一个普通表单字段,还是属于一个文件表单字段,如果是普通表单字段则返回 true,否则返回 false。
public String getName() -- 依据RFC1867协议返回的是filename的内容。以上文例子为例,返回值将是“file1.txt” 或 “file2.gif”。如果 FileItem 类对象对应的是普通表单字段,getName 方法将返回 null。
public String getFieldName() -- 依据RFC1867协议返回的是name的内容。以上文例子为例,返回值将是“field1” 或 “pics”。
public void write(File file) -- 用于将 FileItem 对象中保存的主体内容保存到某个指定的文件中。如果 FileItem对象中的主体内容是保存在某个临时文件中,该方法顺利完成后,临时文件有可能会被清除。该方法也可将普通表单字段内容写入到一个文件中,但它主要用途是将上传的文件内容保存在本地文件系统中。
public boolean isInMemory() -- 用来判断 FileItem 类对象封装的主体内容是存储在内存中,还是存储在临时文件中,如果存储在内存中则返回 true,否则返回false。
public void delete() -- 用来清空 FileItem 类对象中存放的主体内容,如果主体内容被保存在临时文件中,delete 方法将删除该临时文件。
上传文件的保存:
File uploadedFile = new File(...);
item.write(uploadedFile);
四)注意点:
对于fileupload,一共有3种上传文件的处理方式:
DiskFileUpload, ServletFileUpload, PortlerFileUpload
他们的区别是:
ServletFileUpload 最常用的类,大多情况我们就用它了。
DiskFileUpload 已被标记为Deprecated,由ServletFileUpload取代。
PortletFileUpload 需配合portlet的api一起使用(本人至今没用过 = =!)