很久以前翻译着玩的东东,又被我翻出来了。
=========================================================
The Apache Commons Project 中的 FileUpload (官方网址
)
翻译:angryzorro
概述
Apache Commons 中的 FileUpload 包能够使你更容易地向 servlet 和 web应用 中添加健壮的高性能的文件上传功能.
FileUpload 解析符合 RFC 1867
标准 "Form-based File Upload in HTML" 的 HTTP 请求.也就是说,如果使用 POST 方法提交一个
HTTP 请求,且其中的内容类型是 "multipart/form-data",那么 FileUpload
就会解析该请求,在某种意义上使得结果对调用者来说更易于使用.
用户向导
1 使用 FileUpload
FileUpload
的使用可以有许多不同的方法,这依赖于你的应用的需求.在最简单的情况下,你只要调用一个单一的方法来解析 servlet
请求,然后处理将要应用到你的应用的项目列表.另一种极端的情况下,你有可能会决定自定义 FileUpload
来完全控制个别项目被存储的方式;例如,你可能会决定把文件内容作为流存入数据库中.
这里,我们将描述 FileUpload 的基本原理,并例举一些较为简单而且最普通的使用模式.FileUpload 的自定义将会在别处
描述.
FileUpload 需要依赖 Commons IO,因此在继续之前你需要确定你的类路径中已经存在了"依赖关系"页面
中所提及的 Commons IO 版本.
2 工作原理
一个文件上传请求由一组有序的项目列表组成,这些项目是依据 RFC 1867
标准 "Form-based File Upload in HTML" 编码.FileUpload 能够解析这种请求,并提供给你的应用一组包含各个上传项目的列表.每个这样的项目都实现了 FileItem 接口,无论它的根本实现是什么.
本页描述的是 commons fileupload 库的传统API.传统API 是一条捷径.然而,为了最终的性能,你可能更喜欢速度更快的 流API
.
每个文件项目都有许多的属性,它们可能对你的应用很有用.比如说,每个文件项目有一个名称属性和一个内容类型属性,并
且提供一个 InputStream
来访问它的数据.另一方面,你可能需要对多个文件项目进行不同的处理,这依赖于处理的项目是否是一个常规的表单域(即数据来自一个通常的文本框或类似的
HTML域)或是一个被上传的文件.FileItem 接口提供一些方法来对此做出判定,并用最合适的方式访问数据.
FileUpload 通过 FileItemFactory 创建新的文件项目,正是它给了
FileUpload 极大的适应性.工厂对每个项目如何创建拥有最终控制权.通常由 FileUpload
运载的工厂执行会将项目数据存储在内存中或者磁盘上,这取决于项目的大小(即数据字节数).然而,这一行为可以通过自定义来更适合你的应用.
3 Servlets 和 Portlets
FileUpload 从1.1版开始支持在 servlet 和 portlet 两种环境下的文件上传请求.它在这两种环境下的用法基本上是一致的,所以本文接下来的部分将只涉及 servlet 环境.
如果你的应用是建立在 portlet 环境下的,那么在阅读本文时应按照以下2点做出区别:
·在你看到的涉及 ServletFileUpload 类的地方,用 PortletFileUpload 类替换.
·在你看到的涉及 HttpServletRequest 类的地方,用 ActionRequest 类替换
4 请求的解析
在你使用一个已经上传的项目工作之前,理所当然你需要对请求做出解析.确认请求是否确实是一个文件上传请求是一个直接了当的做法,但是 FileUpload 自身提供了一个静态方法来使这件事更简单.
// check that we have a file upload request
boolean
isMultipart = ServletFileUpload.isMultipartContent
(
request
);
现在我们已经准备好将解析请求的各个组成项.
4.1 最简单的情况
最简单的使用方案如下:
·上传的项目应当被保持在内存中,只要他们相当地小.
·大的项目应该被写入磁盘上的一个临时文件.
·非常大的文件的上传请求应该是不被允许的.
·接受内置的可以保持在内存的项目最大值,可以上传的文件的最大值和存放临时文件的路径的默认值.
在这种方案下的对请求的操作再简单不过了:
// 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
);
这就是所有要做的.真的!
解析后的结果是一个文件项目的 List,每个文件项目都实现了 FileItem 接口.对这些项目的处理将会在后面讨论.
4.2 练习更多的控制
如果你的使用方案与上面所描述的最简单的用例很接近,但是你需要更多一点的控制,那么你可以很容易地自定义上传处理器或者文件项目工厂的行为,又或者同时自定义两者的行为.接下来的例子展示了几个配置选项:
// Create a factory for disk-based file items
DiskFileItemFactory factory = new
DiskFileItemFactory();
// Set factory constraints
factory.setSizeThreshold(yourMaxMemorySize
);
factory.setRepository(yourTempDirectory
);
// Create a new file upload handler
ServletFileUpload upload = new
ServletFileUpload(factory
);
// Set overall request size constraint
upload.setSizeMax(yourMaxRequestSize
);
// Parse the request
List
/* FileItem */ items = upload.parseRequest(request
);
当然,每一个配置方法都与其他的无关,但是如果你想要一次性对工厂进行配置,可以使用另一个可供选择的构造函数,就像这样:
// Create a factory for disk-based file items
DiskFileItemFactory factory = new
DiskFileItemFactory(yourMaxMemorySize
, yourTempDirectory
);
如果你还需要更进一步地对请求的解析进行控制,像是把项目存储到别的地方(例如:数据库),那么你应该到 FileUpload 的自定义
查找.
5 处理上传的项目
一旦完成了解析,你会得到一个文件项目的 List 并将对其进行处理.多数情况下,你会想要用不同与处理常规表单域的方法来处理文件上传,所以你可能会这样处理:
// Process the uploaded items
Iterator iter = items.iterator();
while
(iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (item.isFormField()) {
processFormField(item);
} else {
processUploadedFile(item);
}
}
对于常规的表单域,你多数只对项目的名称和字符串值感兴趣.如你所需,访问它们是非常简单的.
// Process a regular form field
if
(item.isFormField()) {
String name = item.getFieldName();
String value = item.getString();
...
}
对于一个文件上传,在你处理其内容之前,你可能想要先知道几个不同的事项.这有一个例子,里面可能有你感兴趣的一些方法.
// Process a file upload
if
(!item.isFormField()) {
String fieldName = item.getFieldName();
String fileName = item.getName();
String contentType = item.getContentType();
boolean
isInMemory = item.isInMemory();
long
sizeInBytes = item.getSize();
...
}
关于上传的文件,一般你是不会想要从内存来对其进行存取的,除非它们非常的小,或是你没有其他的选择.而将其内容作为流来处理,或者把整个文件写入它最终的位置,这样才更合适.FileUpload 对这两种做法都提供了简单的实现方法.
// Process a file upload
if
(writeToFile) {
File uploadedFile = new
File(...);
item.write(uploadedFile);
} else
{
InputStream uploadedStream = item.getInputStream();
...
uploadedStream.close();
}
注意,在 FileUpload 的默认实现中,如果数据已经存在于临时文件中,write() 将试图将文件重命名为指定的目的文件.实际上,只有因为某些原因重命名失败了或者是数据存放在内存中的情况下才会去复制数据.
如果你需要在内存中存取上传的数据,你只要调用get()方法来获取数据的字节数组.
// Process a file upload in memory
byte
[] data = item.get();
...
6 清理资源
本节只适用于你使用 DiskFileItem
的情况.换句话说,就是在你处理上传的数据之前它们被存放在临时文件中.
这些临时文件在不再被使用的时候(如果相应的java.io.File是可回收的则更好)会自动被删除.这会被org.apache.commons.io.FileCleaningTracker的一个实例启动的一个收割线程默默执行.
在下文中,我们假定你正在编写一个web应用.在一个web应用中,资源清理是被javax.servlet.ServletContextListener的一个实例控制的.在其他环境中,类似的观念定是适用的.
6.1 FileCleanerCleanup 类
你的web应用应该使用org.apache.commons.fileupload.FileCleanerCleanup的一个实例.那很简单,你只要把它加到你的 web.xml 中:
<web-app>
...
<listener>
<listener-class>
org.apache.commons.fileupload.servlet.FileCleanerCleanup
</listener-class>
</listener>
...
</web-app>
6.2 创建一个 DiskFileItemFactory
FileCleanerCleanup 提供一个
org.apache.commons.io.FileCleaningTracker 实例.此实例必须在创建一个
org.apache.commons.fileupload.disk.DiskFileItemFactory
时使用.这应该通过调用如下方法来实现:
public static
DiskFileItemFactory newDiskFileItemFactory(ServletContext context, File repository) {
FileCleaningTracker fileCleaningTracker = FileCleanerCleanup.getFileCleaningTracker(context);
return new
DiskFileItemFactory(fileCleaningTracker,
DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD
,
repository);
}
6.3 禁用临时文件的清理
要禁用对临时文件的追踪,你就要设置 FileCleaningTracker 的值为null.从而,创建的文件将不再被追踪,也就不再会被自动删除.
7 与病毒扫描器交互
病毒扫描器与web容器运行在同一个系统上会引发使用 FileUpload 的应用产生一些意外的情况.本节描述了一些你可能遭遇到的情况,并提供了一些处理这些问题的建议.
FileUpload
的默认实现会使得超过某一大小限制的上传项被写入到磁盘.当这样一个文件一完成,系统中的病毒扫描器就会激活并开始检查它,并有可能将其隔离,即将其转移
到一个特殊的位置,在那里它不会引起任何问题.这无疑会给应用开发者一个出其不意,因为上传的文件项将无法再进行处理.另一方面,低于那个大小限制的上传
项将被存放在内存中,因此不会被病毒扫描器发现.这使得病毒有可能以某种形式被保留来下(但是它一旦写入到磁盘,病毒扫描器就会锁定并检查它).
一个普遍使用的解决方案是将所有上传的文件都放在系统的一个固定的路径下,并且设置病毒扫描器忽略该路径.这样能够确保文件不会从应用中强行移出,但却将
病毒扫描的责任留给了应用开发者.对上传文件进行病毒扫描可以由外部程序来执行,它可能会将干净的或是被清理过的文件移动至一个"认可的"路径,病毒扫描
也可通过应用自身内部整合的病毒扫描器来执行.关于配置一个外部程序或者整合病毒扫描到应用已经超出了本文内容范围.
8 进度监视
如果你有大文件上传的需求,那么让你的用户知道已经接收到的大小将会十分体贴.正好 HTML 页面允许通过返回一个 multipart/replace 响应或者类似的东西来实现一个进度条.
监视上传进度可以通过加入一个进度监听器来做到:
//Create a progress listener
ProgressListener progressListener = new
ProgressListener(){
public void
update(long
pBytesRead, long
pContentLength, int
pItems) {
System.out
.println("We are currently reading item "
+ pItems);
if
(pContentLength == -1) {
System.out
.println("So far, "
+ pBytesRead + " bytes have been read."
);
} else
{
System.out
.println("So far, "
+ pBytesRead + " of "
+ pContentLength
+ " bytes have been read."
);
}
}
}
upload.setProgressListener(progressListener);
自己动手照上面的样子实现你的第一个进度监听器,你会发现一个缺陷:这个进度监听器的调用频率很高.根据 servlet
引擎和其他环境工厂,它可能因任何网络数据包而调用!换句话说,你的进度监听器会成为一个性能问题!一个典型的解决方案是减少进度监听器的活动.例如,可
能你只是发送一条消息,倘若兆字节数发生了变化:
//Create a progress listener
ProgressListener progressListener = new
ProgressListener(){
private long
megaBytes = -1;
public void
update(long
pBytesRead, long
pContentLength, int
pItems) {
long
mBytes = pBytesRead / 1000000;
if
(megaBytes == mBytes) {
return
;
}
megaBytes = mBytes;
System.out
.println("We are currently reading item "
+ pItems);
if
(pContentLength == -1) {
System.out.println("So far, "
+ pBytesRead + " bytes have been read."
);
} else
{
System.out.println("So far, "
+ pBytesRead + " of "
+ pContentLength
+ " bytes have been read."
);
}
}
}
9 接下来做什么
希望本文使你在自己的应用程序中如何使用 FileUpload 有了一个清晰的概念.对于这里介绍的和其他的可用的方法的更多细节请参考 JavaDocs
.
这里描述的用法应该能够满足绝大部分的文件上传需求.然而,要是你有更复杂的需求,FileUpload 也仍然能够通过其灵活的自定义
能力帮助你.
分享到:
相关推荐
在Java Web环境中,我们可以利用JavaServer Pages (JSP) 和Apache Commons FileUpload库来实现这个功能。本项目就是围绕这个主题展开,它演示了如何在JSP中集成Apache Commons FileUpload来处理文件上传。 【描述】...
本教程将详细介绍如何使用Servlet和Apache的Commons FileUpload库来实现这一功能。在本例中,开发环境为myEclipse,这是一个强大的Java集成开发环境。 首先,你需要在项目中引入两个关键的库:`commons-fileupload-...
“工具”标签可能指的是一些辅助工具或者最佳实践,如使用Maven或Gradle来管理Apache Commons FileUpload依赖,或者是IDE中的调试技巧,帮助开发者更好地理解和使用这个库。 在压缩包文件名列表中,我们看到的是一...
Apache Commons FileUpload库提供了处理多部分表单数据(即文件上传)的工具,使得我们可以方便地解析请求中的文件。 Apache Commons FileUpload库主要涉及以下两个关键类: 1. `DiskFileItemFactory`:这是文件项...
在Java Web应用中,我们可以使用Servlet API或者第三方库如Apache Commons FileUpload来处理这些文件。以下是一个简单的Servlet实现多文件上传的步骤: 1. **HTML表单设计**: 创建一个`...
2. **文件上传组件**:在JSP中,通常使用Apache的Commons FileUpload库来处理文件上传。这个库提供了解析HTTP请求中的多部分数据(multipart/form-data),并处理文件上传的功能。 3. **Servlet**:在JSP中,文件...
8. **commons-fileupload-1.2.2.jar**:Apache Commons FileUpload库处理HTTP请求中的多部分/表单数据,特别适用于处理文件上传功能。 9. **commons-dbutils-1.4.jar**:Apache Commons DbUtils是一个简化数据库...
`Commons FileUpload`库(Apache Commons IO)是一个常用的工具,它提供了解析多部分请求的API。首先,我们需要在Servlet中添加依赖,并使用`FileItemFactory`和`ServletFileUpload`来解析请求: ```java import ...
在Java中,有多种方式可以实现文件上传功能,其中包括使用Servlet API以及第三方库如Apache Commons FileUpload。下面我们将详细探讨这些方法。 首先,Java Servlet API提供了一种基础的文件上传方式。在Servlet ...
Struts 1 是一个经典的Java Web开发框架,它在2000年代初期非常流行,为MVC(Model-...此外,还能理解Apache Commons FileUpload库的工作原理,这对任何想要深入理解Struts 1和文件上传的开发者来说都是非常有价值的。
- **commons-fileupload-1.3.jar**:Commons FileUpload是一个用于解析HTTP multipart请求的工具,主要用于处理文件上传。 - **commons-io-2.0.1.jar**:Apache Commons IO提供了对Java标准IO库的扩展和改进。 - ...
例如,可以查看`org.apache.struts.upload.MultipartRequestHandler`类来了解其如何处理多部分请求,以及`org.apache.struts.upload.CommonsMultipartRequestHandler`(如果使用了Apache Commons FileUpload库)是...
FileUpload的下载地址是http://commons.apache.org/fileupload/,而Commons-IO的下载链接是http://commons.apache.org/io/。 9. iReport和JasperReport:这两款组件是用于报表设计和生成的工具,支持复杂的报表布局...
7. commons-fileupload-1.2.1.jar - Apache Commons FileUpload,处理HTTP多部分上传请求的库。 接下来,我们将按照以下步骤在Eclipse中配置Struts2: 步骤1:创建Java Web项目 在Eclipse中,选择"File" -> "New" ...
接下来,项目依赖了两个Apache Commons库,`commons-io-2.5.jar`和`commons-fileupload-1.3.2.jar`。`commons-io`提供了对I/O操作的支持,而`commons-fileupload`则用于处理HTTP请求中的文件上传,这对于用户上传...
Java中的文件上传主要依赖于`Commons FileUpload`库,这是Apache Commons项目的一部分,专门用于处理HTTP请求中的多部分数据,也就是通常所说的表单数据。要使用FileUpload库,我们需要在项目中引入对应的jar包,如`...
5. **Apache Commons库**:Struts2使用了一些Apache Commons项目提供的库,如commons-logging.jar、commons-fileupload.jar等,它们分别用于日志记录和文件上传功能。 6. **开发工具**:对于IDEA这样的开发环境,...
- **MultiPart解析**:使用Apache Commons FileUpload库或者Spring MVC的MultiPartResolver,解析HTTP请求中的multipart/form-data数据类型,以支持文件上传。用户选择文件后,这些文件会被分割成多个部分并发送到...
在Servlet 3.0及以上版本中,可以使用`HttpServletRequest`的`getPart()`方法直接处理多部分请求,而在老版本中,通常需要依赖第三方库如Apache Commons FileUpload。 描述中提到的"默认上传到D盘"意味着在服务器端...
另外,Apache Commons FileUpload库是一个常用的第三方库,它简化了文件上传的处理,可以处理大文件和多文件上传。 4. **SWF文件上传的特殊性**:由于SWF文件可能包含ActionScript代码,所以上传时需要考虑安全性。...