文件上傳下載案例:html
首先是此案例工程的目錄結構:java
處理上傳: FileUploadServlet.javaweb
1 package fnz.fileUploadTest; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.PrintWriter; 7 import java.text.SimpleDateFormat; 8 import java.util.Date; 9 import java.util.HashMap; 10 import java.util.List; 11 import java.util.Map; 12 13 import javax.servlet.ServletException; 14 import javax.servlet.http.HttpServlet; 15 import javax.servlet.http.HttpServletRequest; 16 import javax.servlet.http.HttpServletResponse; 17 18 import org.apache.commons.fileupload.FileItem; 19 import org.apache.commons.fileupload.FileUploadException; 20 import org.apache.commons.fileupload.disk.DiskFileItemFactory; 21 import org.apache.commons.fileupload.servlet.ServletFileUpload; 22 23 public class FileUploadServlet extends HttpServlet { 24 25 public void doGet(HttpServletRequest request, HttpServletResponse response) 26 throws ServletException, IOException { 27 try { 28 //建立 FileItem 對象的工廠 29 DiskFileItemFactory fileItemFactory = new DiskFileItemFactory(); 30 //負責處理上傳的文件數據,並將表單中每一個輸入項封裝成一個 FileItem 對象中 31 ServletFileUpload sfu = new ServletFileUpload(fileItemFactory); 32 //設置單個文件最大10M 33 sfu.setFileSizeMax(10*1024*1024); 34 //設置總文件最大100M 35 sfu.setSizeMax(100*1024*1024); 36 // 設置編碼,至關於:request.setCharacterEncoding("UTF-8"); 37 sfu.setHeaderEncoding("UTF-8"); 38 //判斷上傳表單是否爲multipart/form-data類型 39 if(sfu.isMultipartContent(request)){ 40 //解析request對象,並把表單中的每個輸入項包裝成一個fileItem 對象,並返回一個保存了全部FileItem的list集合 41 List<FileItem> list = sfu.parseRequest(request); 42 for (FileItem fileItem : list) { 43 //判斷:是不是普通表單字段 44 if(fileItem.isFormField()){ 45 String fieldName = fileItem.getFieldName();//name 46 String value = fileItem.getString();//value 47 System.out.println(fieldName+" "+value); 48 } 49 //不然爲上傳文件 50 else{ 51 //String fieldName = fileItem.getFieldName(); // 表單元素名稱 name 52 String name = fileItem.getName(); // 文件名 53 //String content = fileItem.getString(); // 表單元素名稱, 對應的數據 value 54 //String type = fileItem.getContentType(); // 文件類型 55 //InputStream in = fileItem.getInputStream(); // 上傳文件流 56 // 獲取項目文件夾upload對應服務器上的upload路徑 57 String path = getServletContext().getRealPath("/upload"); 58 59 //用當前時間+文件名 來命名上傳後的文件名 60 SimpleDateFormat time = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss_S"); 61 String str = time.format(new Date()); 62 // b. 與文件名拼接 63 name = str +"#"+ name; 64 65 //建立一個文件 66 File file = new File(path,name); 67 //上傳 68 fileItem.write(file); 69 //刪除系統產生的臨時文件 70 fileItem.delete(); 71 System.out.println("OK"); 72 } 73 } 74 } 75 76 } catch (Exception e) { 77 throw new RuntimeException(e); 78 } 79 80 81 //將文件放入request域中 82 Map<String,String> fileNames = new HashMap<String,String>(); 83 String downFolderPath = getServletContext().getRealPath("/upload"); 84 File file = new File(downFolderPath); 85 String[] files = file.list(); 86 if(files!=null){ 87 for (String fileItem : files) { 88 String[] splitNames = fileItem.split("#"); 89 fileNames.put(fileItem, splitNames[1]!=null?splitNames[1]:fileItem); 90 } 91 } 92 request.setAttribute("fileNames",fileNames); 93 request.getRequestDispatcher("/index.jsp").forward(request, response); 94 } 95 96 public void doPost(HttpServletRequest request, HttpServletResponse response) 97 throws ServletException, IOException { 98 this.doGet(request, response); 99 } 100 101 }
處理下載:FileDownLoadServlet.java算法
1 package fnz.fileUploadTest; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.io.OutputStream; 8 import java.io.PrintWriter; 9 import java.net.URLEncoder; 10 11 import javax.servlet.ServletException; 12 import javax.servlet.http.HttpServlet; 13 import javax.servlet.http.HttpServletRequest; 14 import javax.servlet.http.HttpServletResponse; 15 16 public class FileDownLoadServlet extends HttpServlet { 17 18 public void doGet(HttpServletRequest request, HttpServletResponse response) 19 throws ServletException, IOException { 20 21 // 獲取用戶下載的文件名稱(url地址後追加數據,get) 22 String fileName = request.getParameter("downFileName"); 23 fileName = new String(fileName.getBytes("ISO8859-1"),"UTF-8"); 24 25 // 先獲取上傳目錄路徑 26 String basePath = getServletContext().getRealPath("/upload"); 27 // 獲取一個文件流 28 InputStream in = new FileInputStream(new File(basePath,fileName)); 29 30 // 若是文件名是中文,須要進行url編碼 31 fileName = URLEncoder.encode(fileName, "UTF-8"); 32 // 設置下載的響應頭 33 response.setContentType("application/x-msdownload"); 34 response.setHeader("content-disposition", "attachment;fileName=" + fileName); 35 36 // 獲取response字節流 37 OutputStream out = response.getOutputStream(); 38 byte[] b = new byte[1024]; 39 int len = -1; 40 while ((len = in.read(b)) != -1){ 41 out.write(b, 0, len); 42 } 43 // 關閉 44 out.close(); 45 in.close(); 46 } 47 48 public void doPost(HttpServletRequest request, HttpServletResponse response) 49 throws ServletException, IOException { 50 this.doGet(request, response); 51 } 52 53 }
前臺操做和顯示:index.jspapache
1 <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> 2 <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>FileUpload</title> 7 </head> 8 9 <body> 10 <form action="${pageContext.request.contextPath}/FileUploadServlet" method="post" enctype="multipart/form-data"> 11 <input type="file" name="file1"><br/> 12 <input type="submit" value="提交"> 13 </form> 14 <hr> 15 已上傳的文件,點擊下載<br/> 16 <c:if test="${not empty requestScope.fileNames }"> 17 <c:forEach var="item" items="${requestScope.fileNames}" > 18 <c:url var="url" value="FileDownLoadServlet"> 19 <c:param name="downFileName" value="${item.key}"></c:param> 20 </c:url> 21 <a href="${url }">${item.value }</a><br/> 22 </c:forEach> 23 </c:if> 24 </body> 25 </html>
文件上傳和下載注意事項及解釋:瀏覽器
文件上傳:緩存
<input type="file">標籤用於在web頁面中添加文件上傳輸入項,設置文件上傳輸入項時須注意:
一、必需要設置input輸入項的name屬性,不然瀏覽器將不會發送上傳文件的數據。
2、必須把form的enctype屬性值設爲multipart/form-data.method
提交方式設爲post方式。設置該值後,瀏覽器在上傳文件時,將把文件數據附帶在http請求消息體中,並使用MIME協議對上傳的文件進行描述,以方便接收方對上傳數據進行解析和處理。安全
使用Commons-fileupload組件實現文件上傳服務器
須要導入該組件相應的支撐jar包:Commons-fileupload和commons-io。commons-io 不屬於文件上傳組件的開發jar文件,但Commons-fileupload 組件從1.1 版本開始,它工做時須要commons-io包的支持。app
核心API—DiskFileItemFactory
DiskFileItemFactory 是建立 FileItem 對象的工廠,這個工廠類經常使用方法:
public DiskFileItemFactory(int sizeThreshold, java.io.File repository)
構造函數
public void setSizeThreshold(int sizeThreshold)
設置內存緩衝區的大小,默認值爲10K。當上傳文件大於緩衝區大小時, fileupload組件將使用臨時文件緩存上傳文件。
public void setRepository(java.io.File repository)
指定臨時文件目錄,默認值爲System.getProperty("java.io.tmpdir")
核心API—ServletFileUpload
ServletFileUpload 負責處理上傳的文件數據,並將表單中每一個輸入項封裝成一個 FileItem 對象中。經常使用方法有:
boolean isMultipartContent(HttpServletRequest request)
判斷上傳表單是否爲multipart/form-data類型
List parseRequest(HttpServletRequest request)
解析request對象,並把表單中的每個輸入項包裝成一個fileItem 對象,並返回一個保存了全部FileItem的list集合。
setFileSizeMax(long fileSizeMax)
設置上傳文件的最大值
setSizeMax(long sizeMax)
設置上傳文件總量的最大值
setHeaderEncoding(java.lang.String encoding)
設置編碼格式
setProgressListener(ProgressListener pListener)
上傳文件的處理細節
中文文件亂碼問題
文件名中文亂碼問題,可調用ServletUpLoader的setHeaderEncoding方法,或者設置request的setCharacterEncoding屬性
臨時文件的刪除問題
因爲文件大小超出DiskFileItemFactory.setSizeThreshold方法設置的內存緩衝區的大小時,Commons-fileupload組件將使用臨時文件保存上傳數據,所以在程序結束時,務必調用FileItem.delete方法刪除臨時文件。
Delete方法的調用必須位於流關閉以後,不然會出現文件佔用,而致使刪除失敗的狀況。
文件存放位置
爲保證服務器安全,上傳文件應保存在應用程序的WEB-INF目錄下,或者不受WEB服務器管理的目錄。
爲防止多用戶上傳相同文件名的文件,而致使文件覆蓋的狀況發生,文件上傳程序應保證上傳文件具備惟一文件名。
爲防止單個目錄下文件過多,影響文件讀寫速度,處理上傳文件的程序應根據可能的文件上傳總量,選擇合適的目錄結構生成算法,將上傳文件分散存儲。
ProgressListener progressListener = new ProgressListener() {
public void update(long pBytesRead, long pContentLength, int pItems) {
System.out.println("到如今爲止, " + pBytesRead + " 字節已上傳,總大小爲 "
+ pContentLength);
}
};
upload.setProgressListener(progressListener);
long temp = -1; //temp注意設置爲類變量
long ctemp = pBytesRead /1024;
if (mBytes == ctemp)
return;
temp = mBytes;
Web應用中實現文件下載的兩種方式
超連接直接指向下載資源
程序實現下載需設置兩個響應頭:
設置Content-Type 的值爲:application/x-msdownload。Web 服務器須要告訴瀏覽器其所輸出的內容的類型不是普通的文本文件或 HTML 文件,而是一個要保存到本地的下載文件。
Web 服務器但願瀏覽器不直接處理相應的實體內容,而是由用戶選擇將相應的實體內容保存到一個文件中,這須要設置 Content-Disposition 報頭。該報頭指定了接收程序處理數據內容的方式,在 HTTP 應用中只有 attachment 是標準方式,attachment 表示要求用戶干預。在 attachment 後面還能夠指定 filename 參數,該參數是服務器建議瀏覽器將實體內容保存到文件中的文件名稱。在設置 Content-Dispostion 以前必定要指定 Content-Type
由於要下載的文件能夠是各類類型的文件,因此要將文件傳送給客戶端,其相應內容應該被當作二進制來處理,因此應該調用response.getOutputStream()方法返回 ServeltOutputStream 對象來向客戶端寫入文件內容。
byte[] b = new byte[1024]; int len = -1; while ((len = in.read(b)) != -1){ out.write(b, 0, len); }