文件的上傳和下載—上傳的實現,注意事項

 實現WEB開發中的文件上傳功能,需完成如下二步操作:

在WEB頁面中添加上傳輸入項,<input type=“life” name=“”>,使用時注意:

1. 必須要設置input輸入項的name屬性,否則瀏覽器將不會發送上傳文件的數據。

2. 必須把input項的enctype屬值設爲multipart/form-data.設置該值後,瀏覽器在上傳文件時,將把文件數據附帶在http請求消息體中,並使用MIME協議對上傳的文件進行描述,以方便接收方對上傳數據進行解析和處理。

如何在Servlet中讀取文件上傳數據,並保存到服務器本地硬盤中?

Request對象提供了一個getInputStream()方法,使用這個方法可以獲取瀏覽器提交過來的輸入流。但如果瀏覽器上傳多個文件時,我們應該如何區分開來?這是一項複雜的工作。

爲了方便用戶處理文件上傳數據,Apache開源組織提供了用於處理上面應用的開源組件——Commons-fileupload。這個組件使用簡單,性能也比較優異,所以幾乎都使用它來實現上傳文件的處理功能。

DiskFileItemFactory是創建FileItem對象的工廠,這個工廠常用方法:

1. public DiskFileItemFactory(int sizeThreshold, java.io.File repository),常用的構造函數。

2. public void setSizeThreshold(int sizeThreshold),設置內存緩衝區的大小,默認值爲10K。當上傳文件大於緩衝區大小時, fileupload組件將使用臨時文件緩存上傳文件。

3. public void setRepository(java.io.File repository),指定臨時文件目錄,默認值爲System.getProperty("java.io.tmpdir")。

 

ServletFileUpload 負責處理上傳的文件數據,並將表單中每個輸入項封裝到一個FileItem對象中。常用方法有:

1. boolean isMultipartContent(HttpServletRequest request),判斷上傳表單是否爲上傳表單類型。

2. List parseRequest(HttpServletRequest request),解析request對象,並把表單中的每一個輸入項包裝到一個fileItem 對象中,並返回一個保存了所有FileItem的list集合。

3. setFileSizeMax(long fileSizeMax),設置上傳文件的最大尺寸值。

4. setSizeMax(long sizeMax),設置上傳文件總量的最大值。

5. setHeaderEncoding(java.lang.String encoding),設置編碼格式。如果文件路徑中存在中文可能會造成文件路徑亂碼,用此方法處理可以解決。

 

上傳文件案例:

  1. public class FileuploadServlet extends HttpServlet {   
  2.   
  3.   
  4.   
  5. public void dopost(HttpServletRequest request, HttpServletResponse response)   
  6.   
  7. throws ServletException, IOException {   
  8.   
  9. // 創建文件處理工廠,它用於生成FileItem對象。   
  10.   
  11. DiskFileItemFactory difactory = new DiskFileItemFactory();   
  12.   
  13. //設置緩存大小,如果上傳文件超過緩存大小,將使用臨時目錄做爲緩存。   
  14.   
  15. difactory.setSizeThreshold(1024 * 1024);   
  16.   
  17.   
  18.   
  19. // 設置處理工廠緩存的臨時目錄,此目錄下的文件需要手動刪除。   
  20.   
  21. String dir = this.getServletContext().getRealPath("/");   
  22.   
  23. File filedir = new File(dir + "filetemp");   
  24.   
  25. if (!filedir.exists())   
  26.   
  27. filedir.mkdir();   
  28.   
  29. difactory.setRepository(filedir);   
  30.   
  31.   
  32.   
  33. // 設置文件實際保存的目錄   
  34.   
  35. String userdir = dir + "files";   
  36.   
  37. File fudir = new File(userdir);   
  38.   
  39. if (!fudir.exists())   
  40.   
  41. fudir.mkdir();   
  42.   
  43.   
  44.   
  45. // 創建request的解析器,它會將數據封裝到FileItem對象中。   
  46.   
  47. ServletFileUpload sfu = new ServletFileUpload(difactory);   
  48.   
  49. // 解析保存在request中的數據並返回list集合   
  50.   
  51. List list = null;   
  52.   
  53. try {   
  54.   
  55. list = sfu.parseRequest(request);   
  56.   
  57. } catch (FileUploadException e) {   
  58.   
  59. e.printStackTrace();   
  60.   
  61. }   
  62.   
  63.   
  64.   
  65. // 遍歷list集合,取出每一個輸入項的FileItem對象,並分別獲取數據   
  66.   
  67. for (Iterator it = list.iterator(); it.hasNext();) {   
  68.   
  69. FileItem fi = (FileItem) it.next();   
  70.   
  71. if (fi.isFormField()) {   
  72.   
  73. System.out.println(fi.getFieldName());   
  74.   
  75. System.out.println(fi.getString());   
  76.   
  77. } else {   
  78.   
  79. //由於客戶端向服務器發送的文件是客戶端的全路徑,在這我們只需要文件名即可   
  80.   
  81. String fifilename = fi.getName();   
  82.   
  83. int index = filename.lastIndexOf("\\");   
  84.   
  85. if(index != -1)   
  86.   
  87. filenamefilename = filename.substring(index+1);   
  88.   
  89. //向服務器寫出文件   
  90.   
  91. InputStream in = fi.getInputStream();   
  92.   
  93. FileOutputStream fos = new FileOutputStream(fudir + "/" +filename);   
  94.   
  95. byte[] buf = new byte[1024];   
  96.   
  97. int len = -1;   
  98.   
  99. while((len = in.read(buf)) != -1){   
  100.   
  101. fos.write(buf, 0, len);   
  102.   
  103. }   
  104.   
  105. // 關閉流   
  106.   
  107. if(in != null){   
  108.   
  109. try{   
  110.   
  111. in.close();   
  112.   
  113. }finally{   
  114.   
  115. if(fos!=null)   
  116.   
  117. fos.close();   
  118.   
  119. }   
  120.   
  121. }   
  122.   
  123. }   
  124.   
  125. }   
  126.   
  127. }   
  128.   
  129.   
  130.   
  131. public void doGet(HttpServletRequest request, HttpServletResponse response)   
  132.   
  133. throws ServletException, IOException {   
  134.   
  135. doPost(request, response);   
  136.   
  137. }   
  138.   
  139. }   



 

 

上傳文件的處理細節(1):

1. 中文文件亂碼的問題,可以調用兩個方法來設置字符編碼:servletUpLoader.setHeaderEncoding()或request.setCharacterEncoding()。我們可以在源文件的創建ServletFileUpload對象後邊添加如下代碼:

sfu.setHeaderEncoding("UTF-8");



2. 臨時文件的刪除,如果臨時文件大於setSizeThreshold設置的緩存大小,Commons-fileupload組件將使用setRepository設置的臨時目錄來保存上傳的文件,上傳完成後我們需要手動調用FileItem.delete來刪除臨時文件。建議不要修改緩存區大小,如果設置緩存爲1MB,1000個用戶上傳文件就需要1000MB內存,服務器會受不了的。我們刪除掉setSizeThreshold的代碼,並在每次完成一個文件後添加下而的代碼:

// 刪除臨時目錄中的文件

fi.delete();



上傳文件的處理細節(2):

1. 在上面的代碼中,我們將文件的實際保存目錄設置在WEB-INF目錄之外。這樣外部可以直接訪問被上傳的文件,這會造成安全問題。比如用戶上傳了一個帶有惡意腳本功能的JSP文件,然後從外部訪問執行了JSP文件…後果不堪設想。所以我們將源代碼中對應位置處修改如下:

// 之所以放在"WEB-INF"目錄下是爲了防止上傳的文件被直接被訪問的安全問題

String userdir = dir + "WEB-INF/files";



2. 一個WEB應用會許多不同的用戶訪問,不同的用戶可能會上傳相同名稱的文件,如果這樣可能會造成文件覆蓋的情況發生,所以我們必須保證文件名稱的唯一性,我編寫一個方法來生成唯一性名稱的文件名:

/**

* 生成具有唯一性的UUID文件名稱

* @param fileName

* @return

*/

private String uuidName(String fileName){

UUID uuid = UUID.randomUUID();

return uuid.toString() + "_" + fileName;

}

我們將代碼“filename = filename.substring(index + 1);”修改爲:filename = uuidName(filename.substring(index + 1));

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章