文件上傳與下載

文件上傳

實現web開發中的文件上傳功能,操作步驟:
        1.在web頁面中添加上傳輸入項。
        2.在servlet中讀取上傳文件的數據,並保存到本地硬盤中。
<input type=“file”>標籤用於在web頁面中添加文件上傳輸入項,設置文件上傳輸入項時須注意
1.必須要設置input輸入項的name屬性,否則瀏覽器將不會發送上傳文件的數據。
2.必須把form的enctype屬值設爲“multipart/form-data
2.必須把form的method屬性設置爲post方式。
附加知識:
        enctype屬性規定在發送表單數據之前如何對其進行編碼。屬性可能的值:
application/x-www-form-urlencoded 在發送前編碼所有字符(默認)。
multipart/form-data 不對字符編碼。在使用包含文件上傳控件的表單時,必須使用該值。
text/plain 空格轉換爲 "+" 加號,但不對特殊字符編碼。

方式1:手動實現文件上傳

案例中上傳的文件a.txt


web頁面:


  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  2. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  3. <html>
  4. <head>
  5. <title>手動執行文件上傳</title>
  6. <meta http-equiv="pragma" content="no-cache">
  7. <meta http-equiv="cache-control" content="no-cache">
  8. <meta http-equiv="expires" content="0">
  9. <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
  10. <meta http-equiv="description" content="This is my page">
  11. <!--
  12. <link rel="stylesheet" type="text/css" href="styles.css">
  13. -->
  14. </head>
  15. <body>
  16. <form action="${pageContext.request.contextPath }/TestServlet" method="post" enctype="multipart/form-data">
  17. 用戶名:<input type="text" name="userName"/><hr/>
  18. 文件:<input type="file" name="file1"/>&nbsp;&nbsp;<input type="submit" value="提交"/>
  19. </form>
  20. </body>
  21. </html>


Servlet手動獲取上傳文件

  1. package com.cn.servlet;
  2. import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import javax.servlet.ServletException;
  6. import javax.servlet.ServletInputStream;
  7. import javax.servlet.http.HttpServlet;
  8. import javax.servlet.http.HttpServletRequest;
  9. import javax.servlet.http.HttpServletResponse;
  10. /**
  11. * 手動獲取文件上傳
  12. * @author liuzhiyong
  13. *
  14. */
  15. public class TestServlet extends HttpServlet {
  16. public void doGet(HttpServletRequest request, HttpServletResponse response)
  17. throws ServletException, IOException {
  18. //獲取表單(POST)提交的數據流
  19. ServletInputStream in = request.getInputStream();
  20. //轉換流
  21. InputStreamReader inStream = new InputStreamReader(in);
  22. //緩衝流
  23. BufferedReader reader = new BufferedReader(inStream);
  24. //輸出數據
  25. String str = null;
  26. while((str=reader.readLine()) != null){
  27. System.out.println(str);
  28. }
  29. //關閉
  30. reader.close();
  31. inStream.close();
  32. in.close();
  33. }
  34. public void doPost(HttpServletRequest request, HttpServletResponse response)
  35. throws ServletException, IOException {
  36. this.doGet(request, response);
  37. }
  38. }


效果:


由於手動上傳文件,需要另外去解析,所以使用現成的工具,詳見方式2.

方式2:文件上傳組件(FileUpload組件,推薦)

         文件上傳功能開發中很常用,Apache組織也提供了文件上傳組件,FileUpload組件。

FileUpload組件使用步驟:

        下載組件,引入jar文件
           commons-fileupload-1.2.1.jar
           commons-io-1.4.jar
         共2個jar包,點擊打開鏈接,即可使用其API了。

FileUpload組件API:

|-Interface FileItemFactory 文件上傳工廠類(把每一個請求表單項封裝爲一個個FileItem對象)
|--Class DiskFileItemFactory
|----void setRepository(java.io.File repository) 設置臨時緩存目錄

|-Class ServletFileUpload  文件上傳核心類對象,可以獲取所有的FileItem對象
|----List parseRequest(javax.servlet.http.HttpServletRequest request) 獲取所有文件上傳項FileItem
|----boolean isMultipartContent(javax.servlet.http.HttpServletRequest request) 判斷上傳表單是否爲multipart/form-data類型(即判斷當前表單是否爲文件上傳表單),如果是返回true
|----void setFileSizeMax(long fileSizeMax) 設置單個文件上傳最大值
|----void setSizeMax(long sizeMax) 設置總的文件最大大小
|----void setHeaderEncoding(java.lang.String encoding) 設置上傳的文件名的編碼,相當於request.setCharacterEncoding(encoding)

|-Interface FileItem 封裝了普通表單項數據以及文件上傳表單數據
|----String getFieldName() 獲取上傳表單元素名稱
|----String getString() 獲取上傳元素值
|----String getString(java.lang.String encoding) 獲取上傳元素值,並處理格式
|----String getContentType() 獲取上傳文件類型【僅上傳文件表單項有數據】
|----InputStream getInputStream() 獲取post方式提交上來的上傳文件流【僅文件上傳表單項有數據】
|----String getName() 獲取上傳文件名
|----void write(java.io.File file) 寫文件到指定文件
|----void delete() 刪除臨時文件

使用FileUpload組件測試:

web頁面

  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  2. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  3. <html>
  4. <head>
  5. <title>手動執行文件上傳</title>
  6. <meta http-equiv="pragma" content="no-cache">
  7. <meta http-equiv="cache-control" content="no-cache">
  8. <meta http-equiv="expires" content="0">
  9. <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
  10. <meta http-equiv="description" content="This is my page">
  11. <!--
  12. <link rel="stylesheet" type="text/css" href="styles.css">
  13. -->
  14. </head>
  15. <body>
  16. <form action="${pageContext.request.contextPath }/FileUpLoadServlet" method="post" enctype="multipart/form-data">
  17. 用戶名:<input type="text" name="userName"/><hr/>
  18. 文件:<input type="file" name="file1"/>&nbsp;&nbsp;<input type="submit" value="提交"/>
  19. </form>
  20. </body>
  21. </html>

Servlet使用組件獲取數據

  1. package com.cn.servlet;
  2. import java.io.BufferedReader;
  3. import java.io.File;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.io.InputStreamReader;
  7. import java.util.List;
  8. import javax.servlet.ServletException;
  9. import javax.servlet.http.HttpServlet;
  10. import javax.servlet.http.HttpServletRequest;
  11. import javax.servlet.http.HttpServletResponse;
  12. import org.apache.commons.fileupload.FileItem;
  13. import org.apache.commons.fileupload.FileItemFactory;
  14. import org.apache.commons.fileupload.disk.DiskFileItemFactory;
  15. import org.apache.commons.fileupload.servlet.ServletFileUpload;
  16. /**
  17. * 文件上傳組件使用
  18. * @author liuzhiyong
  19. *
  20. */
  21. public class FileUpLoadServlet extends HttpServlet {
  22. public void doGet(HttpServletRequest request, HttpServletResponse response)
  23. throws ServletException, IOException {
  24. //1.創建文件上傳工廠類
  25. DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
  26. // fileItemFactory.setRepository(repository);//設置臨時目錄
  27. //2.創建文件上傳核心類對象,可以獲取所有的FileItem對象
  28. ServletFileUpload upload = new ServletFileUpload(fileItemFactory );
  29. // upload.setFileSizeMax(fileSizeMax);//設置單個文件上傳最大值
  30. // upload.setSizeMax(sizeMax);//設置總的文件最大大小
  31. // upload.setHeaderEncoding(encoding);//設置上傳的文件名的編碼,相當於request.setCharacterEncoding(encoding);
  32. //判斷當前表單是否爲文件上傳表單,如果是返回true
  33. if(ServletFileUpload.isMultipartContent(request)){
  34. //3.把請求數據轉換爲FileItem對象的集合
  35. try {
  36. List<FileItem> list = upload.parseRequest(request);//獲取所有文件上傳項FileItem
  37. //遍歷,得到每一個上傳項
  38. for(FileItem item : list){
  39. //判斷是普通表單項,還是文件上傳表單項
  40. if(item.isFormField()){//普通表單
  41. String fieldName = item.getFieldName();//表單元素(這裏是文本框)名稱
  42. String content = item.getString();//表單元素(這裏是文本框)值
  43. // String content = item.getString("utf-8");//表單元素(這裏是文本框)值,並處理編碼
  44. }else{//文件上傳表單
  45. String fieldName = item.getFieldName();//表單元素名稱
  46. String contentType = item.getContentType();//上傳文件類型
  47. String name = item.getName();//文件名
  48. InputStream in = item.getInputStream();//文件流
  49. String content = item.getString();//文件內容
  50. InputStreamReader inStream = new InputStreamReader(in);
  51. //緩衝流
  52. BufferedReader reader = new BufferedReader(inStream);
  53. //輸出數據
  54. String str = null;
  55. while((str=reader.readLine()) != null){
  56. System.out.println(str);
  57. }
  58. item.write(new File("d:/aa文件.txt"));//寫文件
  59. item.delete();//刪除臨時文件
  60. //關閉
  61. reader.close();
  62. inStream.close();
  63. in.close();
  64. }
  65. }
  66. } catch (Exception e) {
  67. //測試
  68. e.printStackTrace();
  69. }
  70. }else{
  71. System.out.println("當前表單不是文件上傳表單,不處理!");
  72. }
  73. }
  74. public void doPost(HttpServletRequest request, HttpServletResponse response)
  75. throws ServletException, IOException {
  76. this.doGet(request, response);
  77. }
  78. }


效果:

控制檯下直接輸出文件流內容

 FileItem類write()寫文件到硬盤的效果:

寫出的文件內容如下:

文件的上傳下載完整案例

需求:

文件上傳完整案例
1.設置單個文件不能超過30M
2.設置總大小不能超過50M
3.上傳目錄:上傳到項目資源目錄下的upload目錄
4.上傳文件不能覆蓋,解決上傳文件名的同名問題

web開始頁面:index.jsp


  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  2. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  3. <html>
  4. <head>
  5. <title>文件上傳與下載</title>
  6. </head>
  7. <body>
  8. <a href="${pageContext.request.contextPath }/upload.jsp">文件上傳</a>
  9. <hr/>
  10. <a href="${pageContext.request.contextPath }/FileServlet?method=downList">文件下載列表</a>
  11. </body>
  12. </html>



 文件上傳頁面:upload.jsp


  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  2. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  3. <html>
  4. <head>
  5. <title>手動執行文件上傳</title>
  6. </head>
  7. <body>
  8. <form action="${pageContext.request.contextPath }/FileServlet?method=upload" method="post" enctype="multipart/form-data">
  9. 用戶名:<input type="text" name="userName"/><hr/>
  10. 文件:<input type="file" name="file1"/>
  11. &nbsp;&nbsp;<input type="submit" value="提交"/>
  12. </form>
  13. <%-- 不提交文件上傳表單,測試 --%>
  14. <a href="${pageContext.request.contextPath }/FileServlet?method=upload">訪問FileUploadServlet試試</a>
  15. </body>
  16. </html>



 文件下載列表:downList.jsp


  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  2. <%-- 引入jstl核心標籤庫 --%>
  3. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
  4. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  5. <html>
  6. <head>
  7. <title>My JSP 'downList.jsp' starting page</title>
  8. <meta http-equiv="pragma" content="no-cache">
  9. <meta http-equiv="cache-control" content="no-cache">
  10. <meta http-equiv="expires" content="0">
  11. <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
  12. <meta http-equiv="description" content="This is my page">
  13. <!--
  14. <link rel="stylesheet" type="text/css" href="styles.css">
  15. -->
  16. </head>
  17. <body>
  18. <table>
  19. <tr>
  20. <th>序號</th>
  21. <th>文件</th>
  22. <th>操作</th>
  23. </tr>
  24. <c:forEach items="${requestScope.fileNameMap }" var="entry" varStatus="varStatus">
  25. <tr>
  26. <td>${varStatus.count }</td>
  27. <td>${entry.value }</td>
  28. <td>
  29. <%-- 方式1 --%>
  30. <%--<a href="${pageContext.request.contextPath}/FileServlet?method=download&fileName=${entry.key}">下載</a>--%>
  31. <%-- 方式2:在JSP頁面中構造一個URL地址 。。注意context不寫,表示默認當前項目路徑下 --%>
  32. <c:url var="url" value="/FileServlet" context="${pageContext.request.contextPath}">
  33. <c:param name="method" value="download"></c:param>
  34. <c:param name="fileName" value="${entry.key }"></c:param>
  35. </c:url>
  36. <%-- 使用上面的地址 --%>
  37. <a href="${url }">下載</a>
  38. </td>
  39. </tr>
  40. </c:forEach>
  41. </table>
  42. </body>
  43. </html>



 Servlet處理

  1. package com.cn.servlet;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.io.OutputStream;
  7. import java.net.URLEncoder;
  8. import java.util.HashMap;
  9. import java.util.List;
  10. import java.util.Map;
  11. import java.util.UUID;
  12. import javax.servlet.ServletException;
  13. import javax.servlet.http.HttpServlet;
  14. import javax.servlet.http.HttpServletRequest;
  15. import javax.servlet.http.HttpServletResponse;
  16. import org.apache.commons.fileupload.FileItem;
  17. import org.apache.commons.fileupload.ProgressListener;
  18. import org.apache.commons.fileupload.disk.DiskFileItemFactory;
  19. import org.apache.commons.fileupload.servlet.ServletFileUpload;
  20. /**
  21. * 處理文件上傳與下載:
  22. * 上傳功能:
  23. 1.設置單個文件不能超過30M
  24. 2.設置總文件大小不能超過50M
  25. 3.上傳目錄:上傳到項目資源目錄下的upload目錄
  26. 4.上傳文件不能覆蓋,解決上傳文件名的同名問題
  27. 下載功能:
  28. 下載文件
  29. * @author liuzhiyong
  30. *
  31. */
  32. public class FileServlet extends HttpServlet {
  33. public void doGet(HttpServletRequest request, HttpServletResponse response)
  34. throws ServletException, IOException {
  35. //獲取請求參數,區分不同的操作類型
  36. String method = request.getParameter("method");
  37. if("upload".equals(method)){
  38. upload(request, response);
  39. }else if("downList".equals(method)){
  40. downList(request, response);
  41. }else if("download".equals(method)){
  42. download(request, response);
  43. }
  44. }
  45. /**
  46. * 進入下載劉表
  47. * 思路:
  48. * 先獲取upload目錄下所有文件的文件名,再保存,跳轉到downList.jsp列表展示
  49. * @param request
  50. * @param response
  51. * @throws ServletException
  52. * @throws IOException
  53. */
  54. private void downList(HttpServletRequest request, HttpServletResponse response)
  55. throws ServletException, IOException{
  56. //1.初始化map集合Map<包含唯一標記的文件名, 簡單文件名>
  57. Map<String, String> fileNameMap = new HashMap<String, String>();
  58. //2.獲取上傳目錄,及其下所有文件的文件名
  59. String bathPath = this.getServletContext().getRealPath("/upload");
  60. //上傳目錄
  61. File file = new File(bathPath);
  62. //獲取上傳目錄下,所有文件名
  63. String[] list = file.list();//返回目錄下的文件或者目錄名,包含隱藏文件。
  64. //遍歷,封裝
  65. if(list!=null && list.length>0){
  66. for(String str : list){
  67. //全名
  68. String fileName = str;
  69. //獲取全名字符#後面的短名
  70. String shortName = fileName.substring(fileName.lastIndexOf("#")+1);
  71. //將全名和短命封裝到Map集合中
  72. fileNameMap.put(fileName, shortName);
  73. }
  74. }
  75. //3.保存到request域對象中
  76. request.setAttribute("fileNameMap", fileNameMap);
  77. //4.轉發到下載列表downList.jsp頁面
  78. request.getRequestDispatcher("/downList.jsp").forward(request, response);
  79. }
  80. /**
  81. * 處理下載
  82. * @param request
  83. * @param response
  84. * @throws ServletException
  85. * @throws IOException
  86. */
  87. private void download(HttpServletRequest request, HttpServletResponse response)
  88. throws ServletException, IOException{
  89. //獲取用戶下載的文件名稱(url地址後面追加的參數fileName的值,此參數是GET方式提交的,所以後面需要處理編碼問題)
  90. String fileName = request.getParameter("fileName");
  91. //處理編碼
  92. fileName = new String(fileName.getBytes("iso-8859-1"), "utf-8");
  93. //現獲取文件上傳的目錄路徑
  94. String basePath = this.getServletContext().getRealPath("/upload");
  95. //文件對象
  96. File file = new File(basePath, fileName);
  97. //獲取一個文件輸入字節流對象
  98. FileInputStream in = new FileInputStream(file);
  99. //如果文件名是中文,需要進行url編碼,不然下載後中文不顯示
  100. fileName = URLEncoder.encode(fileName, "utf-8");
  101. /**
  102. 程序實現下載需設置兩個響應頭:
  103. 設置Content-Type 的值爲:application/x-msdownload。Web 服務器需要告訴瀏覽器其所輸出的內容的類型不是普通的文本文件或 HTML 文件,而是一個要保存到本地的下載文件。
  104. Web 服務器希望瀏覽器不直接處理相應的實體內容,而是由用戶選擇將相應的實體內容保存到一個文件中,這需要設置 Content-Disposition 報頭。該報頭指定了接收程序處理數據內容的方式,
  105. 在 HTTP 應用中只有 attachment 是標準方式,attachment 表示要求用戶干預。在 attachment 後面還可以指定 filename 參數,
  106. 該參數是服務器建議瀏覽器將實體內容保存到文件中的文件名稱。在設置 Content-Dispostion 之前一定要指定 Content-Type.
  107. */
  108. //設置下載的響應頭
  109. // response.setContentType("application/x-msdownload");//但是我發現這裏其實可以不加
  110. response.setHeader("content-disposition", "attachment;fileName=" + fileName);
  111. //獲取response字節流
  112. OutputStream out = response.getOutputStream();//因爲要下載的文件可以是各種類型的文件,所以要將文件傳送給客戶端,其相應內容應該被當做二進制來處理,所以應該調用輸出字節流來向客戶端寫入文件內容。
  113. //緩衝數組
  114. byte[] buff = new byte[1024];
  115. int len = -1;
  116. while((len = in.read(buff)) != -1){
  117. out.write(buff, 0, buff.length);
  118. }
  119. //關閉資源
  120. out.close();
  121. in.close();
  122. }
  123. /**
  124. * 處理上傳
  125. * @param request
  126. * @param response
  127. * @throws ServletException
  128. * @throws IOException
  129. */
  130. private void upload(HttpServletRequest request, HttpServletResponse response)
  131. throws ServletException, IOException{
  132. try {
  133. //1.創建文件上傳工廠類(把每一個請求表單項封裝爲一個個FileItem對象)
  134. DiskFileItemFactory factory = new DiskFileItemFactory();
  135. //2.創建文件上傳核心類對象(可以獲取所有的FileItem對象)
  136. ServletFileUpload upload = new ServletFileUpload(factory);
  137. // //【需求1:設置單個文件不能超過30M】
  138. // upload.setFileSizeMax(30*1024*1024);//30M
  139. // //【需求2:設置總文件大小不超過50M】
  140. // upload.setSizeMax(50*1024*1024);//50M
  141. //【需求1:設置單個文件不能超過200M】
  142. upload.setFileSizeMax(200*1024*1024);//200M
  143. //【需求2:設置總文件大小不超過300M】
  144. upload.setSizeMax(300*1024*1024);//300M
  145. upload.setHeaderEncoding("utf-8");//設置上傳的文件名的編碼,若果沒有設置編碼,當上傳文件名爲中文時,會出現亂碼。
  146. /**
  147. * ProgressListener顯示上傳進度
  148. */
  149. ProgressListener progressListener = new ProgressListener(){
  150. @Override
  151. public void update(long pBytesRead, long pContentLength, int pItems) {
  152. System.out.println("到現在爲止, " + pBytesRead/1024 + " KB已上傳,總大小爲 " + pContentLength/1024 + "KB");
  153. }
  154. };
  155. upload.setProgressListener(progressListener);
  156. //判斷:上傳表單是否爲multipart/form-data類型
  157. if(ServletFileUpload.isMultipartContent(request)){
  158. //3.把請求數據轉換爲FileItem的集合
  159. List<FileItem> list = upload.parseRequest(request);
  160. //遍歷list
  161. for(FileItem item : list){
  162. //判斷普通表單元素,或者文件元素
  163. if(item.isFormField()){//普通表單元素
  164. //獲取元素名稱
  165. String fieldName = item.getFieldName();
  166. //獲取元素名稱對應的值
  167. String value = item.getString("utf-8");
  168. System.out.println(fieldName + ":" + value);
  169. }else{//文件上傳元素
  170. //獲取上傳的文件名
  171. String name = item.getName();
  172. /**
  173. * 問題:文件重命名,防止上傳後覆蓋
  174. * 解決:給用戶添加一個唯一標記
  175. */
  176. //隨機生成一個唯一標記
  177. String uuid = UUID.randomUUID().toString().replace("-", "");
  178. name = uuid + "#" + name;
  179. //獲取上傳的目錄路徑
  180. String basePath = this.getServletContext().getRealPath("/upload");// /斜槓代表當前服務器項目路徑下
  181. //創建文件對象
  182. File file = new File(basePath, name);
  183. //寫文件
  184. InputStream in = item.getInputStream();
  185. item.write(file);
  186. in.close();//關閉流
  187. item.delete();//刪除臨時文件
  188. }
  189. }
  190. }else{
  191. System.out.println("不是文件上傳表單,不處理!");
  192. }
  193. } catch (Exception e) {
  194. e.printStackTrace();
  195. }
  196. }
  197. public void doPost(HttpServletRequest request, HttpServletResponse response)
  198. throws ServletException, IOException {
  199. this.doGet(request, response);
  200. }
  201. }


上傳後服務器中存儲的文件


 下載後的文件


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