Apache common-fileupload用户指南
使用FILE UPLOAD
File Upload有很多不同的使用方式,取决于你的应用程序,最简单的方式是使用一个单独的方法来转换servlet请求,然后处理这些像你的应用发出请求的项。在另一个面,你可能需要决定对哪个项执行完全控制以保存它。比如:你可能会决定把内容保存到数据库中。
这里,我们将描述File Upload的原理,并举例说明一些较为简单--最常使用的模式,关于File Upload的定制,可以在其他其他位置。
File Upload依赖于Commons IO,请确保你的classpath里有对于版本的jar包(相关页面有提及)。
如何工作
一个file upload请求包含一组根据RFC 1867编码的已排序的项目,“基于HTML表单的文件上传”。File Upload能够转换一个请求然后为你的应用程序提供一组单一上传的项目。每个这样的项目都实现了FileItem接口,不太在乎如何具体实现。
这一页介绍了commons fileuplaod库的传统API,传统的API是一个方便的方法。但是,为了最终性能着想,你可能更喜欢使用Streaming API。
每一个文件项都有一些你的应用程序可能感性趣的属性。比如,所有项都有一个名字和内容类型,并且提供了一个输入流去访问它的数据。另一方面,你可能 需要使用不同的方式去处理这些项,依据该项是否一个正则的表单元素(数据是否来自于一个传统的文本框或者类似的表单元素),或者一个上传的文件。文件项接 口提供了方法去实现这个检测,以及相应的方式访问它们的数据。
Servlet和门户组件
从1.1版开始,FileUpload在servlet和门户组件两种环境里提供文件上传请求。用法在两种环境里差不多,所以这篇文档余下的部分只涉及servlet环境。
如果你正在创建一个门户组件应用,你应该区分下面两点和这篇文档的不同之处。
在任何地方看到ServletFileUpload类的参考文献,请用PortletFileUpload类来代替。
在任何地方看到HttpServletRequest 类的参考文献,请用ActionRequest类来代替。
解析请求
当然,在你操作上传组件之前,你需要解析请求自身。确保请求实际上是一个文件上传请求很简单,File Upload的提供了一个静态方法使它非常简单。
// Check that we have a file upload request
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
现在我们可以把请求解析成它的组成项。
最简单的情况
最简单的使用情况如下:
只要上传项足够小,那就应该保存在内存里。
大的项应该被写入硬盘的临时文件文件。
非常大的请求应该被阻止上传。
你的应用默认设置可以保存在内存中的最大大小的项目,最大可上传的请求,以及临时存放上传文件的临时目录是可被接受的。
没有比下面更简单的处理请求的方法了:
// 为基于硬盘文件的项目集创建一个工厂
FileItemFactory factory = new DiskFileItemFactory();
// 创建一个新的文件上传处理器
ServletFileUpload upload = new ServletFileUpload(factory);
// 解析请求
List items = upload.parseRequest(request);
以上就是所有需要做的。真的!
请求被解析后,你会提到一些由实现了FileItem接口的项目组成的集合。我们会在下面讨论这此项目。
运用更多控制
如果你的使用情况和最简单的使用情况差不多,如上所述,但是,如果你需要更多的控制的话,可以选择定义上传处理器和项目工厂的行为,这是委简单的。
// 为基于硬盘文件的项目集创建一个工厂
FileItemFactory factory = new DiskFileItemFactory();
// 设置工厂的约束条件
factory.setSizeThreshold(yourMaxMemorySize);
factory.setRepository(yourTempDirectory);
// 创建一个新的文件上传处理器
ServletFileUpload upload = new ServletFileUpload(factory);
// 设置可请求在最大可上传数据量
upload.setSizeMax(yourMaxRequestSize);
// 解析请求
List items = upload.parseRequest(request);
当然,每个配置都可心独立存在,不过你可以一次性配置工厂的所有配置项,使用一个替代的构造方法可以做到这点,像这样:
// 为基于硬盘文件的项目集创建一个工厂
DiskFileItemFactory factory = new DiskFileItemFactory(
yourMaxMemorySize, yourTempDirectory);
如果你需要相比于解析请求更多的控制,像把项目存到其他地方,比如存到数据库,你需要阅读customizing File Upload。
处理上传项目
当完成请求解析后,你会得到一个由你想要处理的文件项组成的集合。大部分情况下,你会想要把使用文件上传的上传的项处理方法区别于和常规表单处理,你需要这样做:
Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (item.isFormField()) {
processFormField(item);
} else {
processUploadedFile(item);
}
}
对于一个正常的表单项,你只会关心它的name,以及对应的字符串值。和你的预期一样,访问上传项目也非常简单。
if (item.isFormField()) {
String name = item.getFieldName();
String value = item.getString();
...
}
对于一个文件上传项,在你处理它的内容之前,你可能会想要知道几件事情。这里有一个关于你可能感兴趣的一些方法的例子。
if (!item.isFormField()) {
String fieldName = item.getFieldName();
String fileName = item.getName();
String contentType = item.getContentType();
boolean isInMemory = item.isInMemory();
long sizeInBytes = item.getSize();
...
}
对于上传的文件,你通常不会想把它放到内存中,除非它很小,或者你没有其它可替代的方法。恰恰相反,你会把文件当成流来处理,并把整个文件存放到最终位置。File Upload提供了简单的方法来实现这两种处理。
if (writeToFile) {
File uploadedFile = new File(...);
item.write(uploadedFile);
} else {
InputStream uploadedStream = item.getInputStream();
...
uploadedStream.close();
}
注意,在FileUpload的默认实现里,如果数据已经在临时文件中,write方法会试图更改存放到指定目的地的文件名。其实数据的复制只会在由于某种原因重命名失败的时候才会成功,或者当数据在内存中已经存在的时候。
如果你需要访问内存中的数据,你仅仅只需要使用get()方法将数据获取并保存到一个字节数组中。
byte[] data = item.get();
...
资源清理
本节只在你使用DiskFileItem时适用。换句话说,它只适用于你在处理上传项目之前将它们写入临时文件的情况。这些临时文件在不使用(更准确的说,是如果java.io.File的类似实例被垃圾回收了。)的情况下会自动删除。org.apache.commons.io.FileCleaner类会默默的完成这个操作,它会启动一个收割机线程。
这个收割机线程在不使用的时候应该关闭。在一个servlet环境里,使用一个特殊的servlet context listener FileCleanerCleanup来完成这件事情。为了让它起作用,需要在你的web.xml里面加入下面的代码片段:
...
<listener>
<listener-class>
org.apache.commons.fileupload.servlet.FileCleanerCleanup
</listener-class>
</listener>
...
</web-app>
创建一个硬盘文件项工厂
FileCleanerCleanup提供了一个org.apache.commons.io.FileCleaningTracker 的实例,在创建org.apache.commons.fileupload.disk.DiskFileItemFactory的时候一定要使用这个实 例。下面的代码里的方法调用实现了这个步骤。
File repository) {
FileCleaningTracker fileCleaningTracker
= FileCleanerCleanup.getFileCleaningTracker(context);
DiskFileItemFactory factory
= new DiskFileItemFactory(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD,
repository);
factory.setFileCleaningTracker(fileCleaningTracker);
return factory;
}
禁用的清除临时文件
要禁用跟踪临时文件,你要设置FileCleaningTracker为空。因为置空,创建的文件将不会再被跟踪,特别说明,它们也不会再被自动删除。
与病毒扫描器互动
病毒扫描器可能和使用了FileUpload的应用程序运行在同一系统上,这可能会导致web容器执行一些异常的行为。这一节介绍了一些你可能会遇到的异常行为,并且提供了一些方法去处理这些问题。
FileUpload的默认实现会将超出临界值的数据写入硬盘。一旦这个文件关闭,系统上的任何病毒扫描器就是被唤醒并且检测这个文件,可能会隔离 这个文件--将它移动到不会引起问题的特定地方。这个,当然,对于程序开发员来说,由于上传的文件项目将不再访问,会让程序员感到奇怪。而另一方面,处于 临界值之下的数据会被加载到内存中,因此不会被病毒扫描器检测。这允许病毒以某种形式保存在内存中(尽管它曾经被写入到硬盘中,然后被病毒扫描器扫描并隔 离)。
一种常用的解决办法是在系统上设置一个目录来专门保存上传的文件。并且设置病毒扫描器忽略这个目录。这样可以保证应用下的文件不会被分离,但是会分 离程序开发人员和病毒扫描的责任关系。可以提供一个扩展的处理程序来执行病毒扫描,将无毒的,被杀过毒的文件移动到特定的位置,或者集成一个病毒扫描系统 到应用内部。
关于扩展一个处理以及集成一个扫描系统到应用内部的详细内容超出了本文档的范围。
上传进度
如果希望上传非常大的文件,你需要抽向你的用户提供反馈,已经上传了多少。HTML页面允许通过返回一个multipart/replace响应来实现一个进度条,或其它类似的东西。
可以通过使用一个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引擎和其他环境工 厂,它可能会被任何网络数据包调用。换句话说,你的进度条监听器会引起性能问题!可能是一个典型的解决方案,是减少进步条的活动数。比如,只有当上传了1 兆字节的时候才反馈给用户:
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.");
}
}
};
下一步是什么?
希望这篇文章能够给你在应用中使用File Upload提供了一个好的想法。想要更多关于这篇文章中提到的方法的资料,和其它方法一样,你需要参考JavaDocs。
这里描述的使用应满足大部分的文件上传的需要。然而,如果你有更复杂的要求,FileUpload还能以其灵活的定制帮助你。
相关推荐
`common_fileupload详解.doc`文档应该提供了关于库的详细使用指南、API参考和示例代码。通过阅读文档,你可以快速掌握如何在项目中集成和使用`commons-fileupload`。 总的来说,Apache Commons FileUpload库极大地...
- **用户指南**:解释了如何在实际项目中使用 Commons 类库,提供示例代码和最佳实践。 - **FAQ**:常见问题解答,解决在使用 Commons 类库时遇到的常见问题。 - **Mailing List** 和 **论坛**:开发者交流平台,...
### SSH综合配置文件:JavaEE中的SSH整合指南 在JavaEE开发中,SSH(Struts、Spring、Hibernate)是常见的企业级应用开发框架组合。本文将深入探讨如何在项目中整合这三大框架,以实现更高效、灵活的开发流程。 ##...
- Apache Jakarta Common项目的`ognl-VERSION.jar`(OGNL引擎)、`freemarker-VERSION.jar`(Freemarker模板引擎)、`xwork-VERSION.jar`等。 - 其他插件如`struts2-xxx-plugin-VERSION.jar`。 - **环境搭建步骤*...
DNA进化算法及其改进研究样本.doc
内容概要:本文详细介绍了使用Matlab编写的水果识别程序。首先简述了人工智能和机器学习在水果识别领域的应用背景,强调了Matlab作为强大编程环境的优势。接着,文章逐步讲解了水果识别程序的具体实现流程,涵盖数据预处理、特征提取、模型训练以及最终的识别算法实现。每个环节都采用了先进的技术和方法,如图像去噪、大小调整、深度学习算法(特别是卷积神经网络CNN),并通过训练神经网络模型来提升识别精度。此外,还讨论了相关技术手段和技术挑战,展示了Matlab在图像处理和计算机视觉方面的强大能力。 适合人群:对图像处理、机器学习感兴趣的科研人员、学生及工程师。 使用场景及目标:适用于希望深入了解Matlab环境下水果识别程序的设计与实现的研究者;旨在帮助使用者掌握从数据准备到模型部署的一系列技能,为实际项目提供理论支持和技术指导。 其他说明:文中不仅提供了详细的程序实现步骤,还对未来发展方向进行了展望,鼓励更多人参与到水果识别及相关领域的研究中。
scratch少儿编程逻辑思维游戏源码-修复塔.zip
# 压缩文件中包含: 中文文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;
scratch少儿编程逻辑思维游戏源码-天空之球.zip
# 压缩文件中包含: 中文-英文对照文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文-英文对照文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;
scratch少儿编程逻辑思维游戏源码-土豆兄弟.zip
scratch少儿编程逻辑思维游戏源码-小鸟冒险.zip
scratch少儿编程逻辑思维游戏源码-跳进火山.zip
scratch少儿编程逻辑思维游戏源码-跳跃引擎.zip
scratch少儿编程逻辑思维游戏源码-旋转(4).zip
scratch少儿编程逻辑思维游戏源码-死里逃生.zip
# 压缩文件中包含: 中文文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;
# 压缩文件中包含: 中文文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;
HPERP商业软件实施解决方案模板.doc
# 压缩文件中包含: 中文-英文对照文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文-英文对照文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;