BrightLoong's Blog

Apache Commons FileUpload

文件上传
Apache Commons FileUpload是用于解析上传文件的包。这里将其一些简单的特性和使用进行一个大概的介绍。

一.简介

用于解析上传的文件,”Form-based File Upload in HTML”。也就是说,如果使用POST方法提交HTTP请求,并且使用内容类型“multipart / form-data”,则FileUpload可以解析该请求。

二.简单使用

1.满足的条件

  • form表单使用POST请求,并且form表单的内容格式要定义成multipart/form-data格式
  • form表单内,要添加空间<input type="file" name="">或者其他的比如:Uploadify插件

    1
    2
    3
    4
    5
    6
    <form method="POST" enctype="multipart/form-data" action="fup.cgi">
    File to upload: <input type="file" name="upfile"><br/>
    Notes about the file: <input type="text" name="note"><br/>
    <br/>
    <input type="submit" value="Press"> to upload the file!
    </form>

    2.具体使用

  • 使用前判断是否有上传文件的请求
1
2
// Check that we have a file upload request
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
  • 简单的例子
1
2
3
4
5
6
7
8
9
10
11
12
13
// Create a factory for disk-based file items
DiskFileItemFactory factory = new DiskFileItemFactory();

// Configure a repository (to ensure a secure temp location is used),默认会放在System.getProperty("java.io.tmpdir")
ServletContext servletContext = this.getServletConfig().getServletContext();
File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
factory.setRepository(repository);

// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);

// Parse the request
List<FileItem> items = upload.parseRequest(request);
  • 加入一些控制的例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Create a factory for disk-based file items
DiskFileItemFactory factory = new DiskFileItemFactory();

// Set factory constraints
//默认为10k,小于这个值的会放在内容中,否则放在设置的disk路径下
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);

也可以一并配置多个属性

1
2
// Create a factory for disk-based file items
DiskFileItemFactory factory = new DiskFileItemFactory(yourMaxMemorySize, yourTempDirectory);
  • 获取上传的文件信息
1
2
3
4
5
6
7
8
9
// 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();
...
}
  • 保存文件前获取文件的一些方式
1
2
3
4
5
6
7
8
9
// Process a file upload
if (writeToFile) {
File uploadedFile = new File(...);
item.write(uploadedFile);
} else {
InputStream uploadedStream = item.getInputStream();
...
uploadedStream.close();
}

OR

1
2
3
// Process a file upload in memory
byte[] data = item.get();
...

三.清理文件

仅仅适用于DiskFileItem,也就是说在上传前,文件被写入了临时文件,如果不再使用这些临时文件,则需要删除这些临时文件。DiskFileItemFactory有一个属性FileCleaningTracker,设置这个属性可以用来追踪删除临时文件。当这个临时文件不再被使用时将会被立即删除,更精确的说是这个文件对象被垃圾收集器回收时,FileCleaningTracker将启动收割者线程(reaper thread)自动删除这个临时文件。 为了确保这个
后台线程在它不再被需要时被停止,在 servlet 环境里,我们通过一个名叫 FileCleanerCleanup 的 s
ervlet 上下文监听器,在web应用关闭时调用FileCleaningTracker.exitWhenFinished()来终止收割机线
程。在servlet环境中,使用 FileCleanerCleanup,FileCleanerCleanup提供了FileCleaningTracker的一个实例,要让FileCleanerCleanup监听器工作,你需要在 web.xml 增加如下代码:。

1
2
3
4
5
6
7
8
9
<web-app>
...
<listener>
<listener-class>
org.apache.commons.fileupload.servlet.FileCleanerCleanup
</listener-class>
</listener>
...
</web-app>

在使用FileCleanerCleanup,应该像下面这样创建DiskFileItemFactory

1
2
3
4
5
6
7
8
9
10
11
public static DiskFileItemFactory newDiskFileItemFactory(ServletContext context,
File repository) {
//FileCleaningTracker类,这个类用于跟踪要删除的文件
FileCleaningTracker fileCleaningTracker
= FileCleanerCleanup.getFileCleaningTracker(context);
DiskFileItemFactory factory
= new DiskFileItemFactory(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD,
repository);
factory.setFileCleaningTracker(fileCleaningTracker);
return factory;
}

四.上传进度

下面是一个创建进度监听的一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
//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);

但是这样会存在问题,有可能会被频繁的调用而造成性能问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//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.");
}
}
};

如果想在页面展示,可以自己实现一个ProgressListener接口,将进度的相关信息放在session中。通过ajax之类的进行调用。具体可以参照博客– Common-FileUpload带进度条上传

坚持原创技术分享,您的支持将鼓励我继续创作!