使用fileupload
根據你的應用需求,fileupload可以有許多不同的使用方式。在最簡單的情況下,你可以調用一個簡單的方法來解析servlet請求,然後在他們提交到你的應用時處理表單列表。在其它規模的終端上,你也可能決定將fileupload進行自定義,以完全控制個別表單項存儲的方法。比如,你或許會將內容流化來保存到數據中。
在這裏。我們將要描述fileupload的基本使用方法,然後解釋一些更簡單的,以及最常用的使用模式。fileupload的個性化在這裏得到了描述。
它怎麼工作
一個文件上傳請求由有序表單項的列表組成,這些表單是根據RFC1867來編碼的,是在html中基於表單的文件上傳。fileupload能解析這樣一個請求然後向你的應用提供一個單獨的上傳表單項的列表。每一個這樣的表單項實現了FileItem接口,而不需要考慮它潛在的實現方式。每個文件的表單項擁有一系列可能對你的應用有用的屬性,比如,每個項目都有一個名字和文件類型,你就可以提供一個InputStream來取它的數據。從另一方面說,你可能需要對這些選項進行不同的處理,這個可以根據對這個選項是不是一個規則的表單項來判斷,即可以根據這個數據是否來源於普通的文本框或者一個簡單的html表單域,還是一個能被上傳的文件。FileItem接口提供了多種方法來判斷它是否是一個可上傳的文件,然後你就可以用最合適的方式來處理這些數據了。FileUpload使用FileItemFactory來創建新的文件項目。這正是給FileUpload帶來靈活性的原因。這個工廠最終控制每個項目的創建。默認的工廠在內存或者磁盤上保存了項目的數據,這個可以根據項目的大小來定(例如,字節數據)。當然,這個動作可以通過自定義來滿足你應用的需要。
解析請求
在你對要上傳的選項處理之前,很顯然的你得先解析這些請求本身。很直接的就是要確保這個請求是不是一個要上傳的文件,然而FileUpload使這一點簡單化了,你只需提供一個靜態的方法來做到這一點。
//檢查是否是一個文件上傳請求
boolean isMultipart = FileUpload.isMultipartContent(request);
現在我們就可以準備解析這個請求到一個備選的選項了。解析的結果是一個文件選項的List,每個這樣的選項都實現了FileItem接口,處理這些選項將在下面得到討論。
最簡單的情況
最簡單的使用場景可以參照下面:
- 被上傳得選項必須以適度的大小駐留在內存中;
- 比較大的文件上傳選項必須寫入到磁盤的臨時文件中去;
- 大文件上傳請求必須不被允許;
- 默認的駐留內存的選項的最大大小,最大允許的上傳文件請求,和臨時文件的存儲地方是可以接受的;
在這種情景下處理這樣一個請求並不是很簡單的:
//創建一個新的文件上傳句柄
DiskFileUpload upload = new DiskFileUpload();
//解析請求
List /* FileItem */ items = upload.parseRequest(request);
這就是所有我們需要做的,真的!
解析的結果是一個文件項目的List,每一個都實現了FileItem接口。處理這些項目將在下面討論。
練習更多的控制
如果你的使用情景非常接近最簡單的使用方式,在上文中可以看到,但是你需要更多的控制臨界的大小和臨時文件的駐留地址,你可以使用DiskFileUpload類的方法來自定義這些動作,就像這樣:
//創建一個新的文件上傳句柄
DiskFileUpload upload = new DiskFileUpload();
//設置上傳參數
upload.setSizeThrehold(最大內存大小);
upload.setSizeMax(最大請求大小);
upload.setRepositoryPath(臨時目錄);
//解析請求
List /* FileItem */ items = upload.parseRequest(request);
當然,每個配置方法都是獨立於其它的,但是如果你想一次就配置它們,你可以使用可選的parseRequest()方法,像這樣:
// 建立一個新的文件上傳句柄
DiskFileUpload upload = new DiskFileUpload();
// 解析請求
List /* FileItem */ items = upload.parseRequest(request,
內存大小, 允許上傳的最大文件, 臨時目錄);
如果你想更多地控制請求的解析,比如把上傳選項存儲到其它地方,例如,存到數據庫中-你可以參照自定義FileUpload。
處理上傳選項
一旦解析過程完畢,你就可以獲得一個文件選項的List,以便進一步處理。在大多數情況下,你將會根據規則的表單域來不同地處理文件的上傳。所以你可能以這樣的方式來處理:
// 處理上傳的選項
Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (item.isFormField()) {
processFormField(item);
} else {
processUploadedFile(item);
}
}
對於一個規則的表單域來說,你對它感興趣的可能就只有它的名字以及它的字符串值。你也會想到,處理它們是簡單的:
//處理一個規則表單域
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();
...
}
對於這些上傳的文件,你一般不想通過內存來存取它們,除非它們很小,或者你沒有其它好的方法,更進一步,你想將內容當作文件流來處理,或者將整個文件寫到最終的地址。FileUpload提供了簡單的方法來完成這些 操作。
// 處理一個文件上傳的情況
if (writeToFile) {
File uploadedFile = new File(...);
item.write(uploadedFile);
} else {
InputStream uploadedStream = item.getInputStream();
...
uploadedStream.close();
}
注意到,在默認的FileUpload的實現中,write()方法將嘗試把文件改名以將它保存到特定的地點,如果數據已經在臨時文件中了,如果重命名失敗,實際的複製文件就完成了(?),在其它原因看來,或者數據已經在內存中了。如果你的確需要在內存中取上傳的數據,你只需簡單的調用get()方法來把它當作一個字符數組來獲得。
// 在內存中處理一個上傳的文件
byte[] data = item.get();
...
和殺毒軟件的相互作用
應用,這個已經超出了本文檔的討論範圍。
希望這個頁面能提供給你一個好的意見,讓你在你自己的應用中能使用FileUpload。更多關於這裏介紹的方法,以及其它可用的方法,你可以參照api文檔。這裏介紹的用法已經可以滿足大多數的文件上傳的需要了,當然,如果你還有更多的複雜的需求,使用它的靈活的自定義配置的能力,FileUpload一定可以能夠幫助你。
一個簡單的示例:
導入的包有:commons-fileupload.jar---commons-io.jar
index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Upload Page</title>
</head>
<body>
<!-- 必須寫 enctype="multipart/form-data" !!! -->
<form method="post" action="upload" style=" text-align: center" enctype="multipart/form-data">
<input type="file" name="file1"><br>
<input type="file" name="file2"><br>
<input type="file" name="file3"><br>
<input type="submit" name="submit">
</form>
</body>
</html>
web.xml
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<servlet-name>UpLoadAction</servlet-name>
<servlet-class>com.hygj.furong.servlet.UpLoadAction</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UpLoadAction</servlet-name>
<url-pattern>/upload</url-pattern>
</servlet-mapping>
UpLoadAction.java
package com.hygj.furong.servlet;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
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.FileUploadBase.SizeLimitExceededException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
public class UpLoadAction extends HttpServlet {
/**
* Destruction of the servlet. <br>
*/
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}
/**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request
* the request send by the client to the server
* @param response
* the response send by the server to the client
* @throws ServletException
* if an error occurred
* @throws IOException
* if an error occurred
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doPost(request, response);
}
/**
* The doPost method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to
* post.
*
* @param request
* the request send by the client to the server
* @param response
* the response send by the server to the client
* @throws ServletException
* if an error occurred
* @throws IOException
* if an error occurred
*/
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 設置長傳文件的最大值:5M
final long MAX_SIZE = 5 * 1024 * 1024;
// 設置允許上傳文件格式的列表
final String[] allowedExt = new String[] { "jpg", "jpeg", "gif", "txt",
"doc", "docx", "mp3", "wma", "m4a", "rar" };
response.setContentType("text/html");
// 字符編碼爲UTF-8
response.setCharacterEncoding("UTF-8");
// 實例化一個硬盤文件工廠,用來配置文件組建ServletFileUpload
DiskFileItemFactory factory = new DiskFileItemFactory();
// 設置長傳文件時用於臨時存放文件的內存大小,這裏是4K,多餘的部分將臨時存在硬盤
factory.setSizeThreshold(4096);
// 設置存放臨時文件的目錄,web根目錄下的UploadTemp目錄
factory
.setRepository(new File(request.getRealPath("/") + "UploadTemp"));
/**
* 用以上工廠實例化長傳組件
*/
ServletFileUpload sfu = new ServletFileUpload(factory);
// 設置最大上傳尺寸
sfu.setSizeMax(MAX_SIZE);
PrintWriter out = response.getWriter();
// 從request得到 所有 上傳域的列表
List fileList = null;
try {
fileList = sfu.parseRequest(request);
} catch (Exception e) {
// 處理文件尺寸過大異常
if (e instanceof SizeLimitExceededException) {
out.println("文件尺寸超過規定大小:" + MAX_SIZE + "字節<p />");
out.println("<a href=/"index.jsp/">返回</a>");
return;
}
System.out.println(e.getMessage());
}
// 沒有文件長傳
if (fileList == null || fileList.size() == 0) {
out.println("請選擇文件上傳--沒有文件長傳");
out.println("<a href=/"index.jsp/">返回</a>");
return;
}
// 得到所有上傳的文件
Iterator fileItr = fileList.iterator();
// 循環處理所有文件
while (fileItr.hasNext()) {
FileItem fileItem = null;
String path = "";
long size = 0;
// 獲取當前文件
fileItem = (FileItem) fileItr.next();
// 忽略簡單form字段 而不是 上傳域的文件域(<input type="text" />等)
if (fileItem == null || fileItem.isFormField()) {
continue;
}
// 獲取文件的完整路徑
path = fileItem.getName();
// 獲取文件大小
size = fileItem.getSize();
if ("".equals(path) || size == 0) {
out.println("請選擇文件上傳--大小爲0");
out.println("<a href=/"index.jsp/">返回</a>");
return;
}
// 得到去除路徑的文件名
String realName = path.substring(path.lastIndexOf("//") + 1);
// 得到文件的拓展名(無拓展名時將得到全名)
String extName = realName.substring(realName.lastIndexOf(".") + 1);
// 拒絕接收規定文件格式之外的文件類型
int allowFlag = 0;
int allowedExtCount = allowedExt.length;
for (; allowFlag < allowedExtCount; allowFlag++) {
if (allowedExt[allowFlag].equals(extName)) {
break;
}
}
if (allowFlag == allowedExtCount) {
out.println("請上傳一下類型的文件");
for (allowedExtCount = 0; allowFlag < allowedExtCount; allowFlag++) {
out.println("*" + allowedExt[allowFlag]
+ " ");
}
out.println("<a href=/"index.jsp/">返回</a>");
return;
}
long now = System.currentTimeMillis();
// 根據系統時間生成上傳夠保存的文件名
String prefix = String.valueOf(now);
// 保存的最終文件完整路徑,保存在web根目錄下的UploadFile目錄下
String finalName = request.getRealPath("/") + "/UploadFile/"
+ prefix + "." + extName;
try {
// 保存文件
fileItem.write(new File(finalName));
out.println("文件上傳成功. 路徑:"+request.getRealPath("/")+ "/UploadFile目錄下 "+" 以保存爲:" + prefix + "." + extName
+ " 文件大小:" + size + "字節<br>");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
out.println("<a href=/"index.jsp/">繼續上傳</a>");
}
/**
* Initialization of the servlet. <br>
*
* @throws ServletException
* if an error occure
*/
public void init() throws ServletException {
// Put your code here
}
}