JavaWeb(六) IO流實現文件上傳下載


    最近學的東西有點雜,做了和看了寫什么就把它記錄下來。不得不說代碼真的很神奇,需要學習的還很多。

一直沒把文件上傳和下載搞清楚,今天就來動手寫一寫。

一 、依賴如下兩Jar實現的文件上傳。

實現代碼如下:

    基礎實現:

 1 package com.qq.upload;
 2 
 3 import org.apache.commons.fileupload.FileItem;
 4 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
 5 import org.apache.commons.fileupload.servlet.ServletFileUpload;
 6 
 7 import javax.servlet.ServletException;
 8 import javax.servlet.annotation.WebServlet;
 9 import javax.servlet.http.HttpServlet;
10 import javax.servlet.http.HttpServletRequest;
11 import javax.servlet.http.HttpServletResponse;
12 import java.io.*;
13 import java.util.List;
14 @WebServlet("/doUpload")
15 public class Upload  extends HttpServlet {
16 
17     public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
18         //得到上傳文件的保存目錄,將上傳的文件存放在WEB-INF目錄下面 不允許外界直接訪問,保證上傳文件的安全性
19 /*        String savePath  = this.getServletContext().getRealPath("/WEB-INF/upload");*/
20         String savePath = this.getServletContext().getRealPath("/LoadJsp");
21         File file  =new File(savePath);
22         if(!file.exists()&&!file.isDirectory()){
23             System.out.println(savePath+"目標目錄不存在,需要進行創建");
24             file.mkdir();
25 
26         }
27         String message = null;
28         try {
29             //1 創建DiskFileItemFactory工廠
30             DiskFileItemFactory factory = new DiskFileItemFactory();
31             //2 創建一個文件上傳解析器
32             ServletFileUpload upload = new ServletFileUpload(factory);
33             //判斷提交上來的數據是不是表單上的數據
34             upload.setHeaderEncoding("UTF-8");
35             if (!ServletFileUpload.isMultipartContent(req)) {
36                 return;
37             }
38 
39             //4 使用ServletFileUpload解析器來解析上傳數據,解析結果返回的是一個List<FileItem>
40             //集合,每一個FileItem對應一個Form表單的輸入項
41             List<FileItem> list = upload.parseRequest(req);
42             for(FileItem item:list) {
43                 if (item.isFormField()) {
44                     String name = item.getFieldName();
45                     String value = item.getString("UTF-8");
46                     System.out.println(name + "=" + value);
47                 } else {
48                     String filename = item.getName();
49                     System.out.println(filename);
50                     if (filename == null || filename.trim().equals("")) {
51                         continue;
52                     }
53                     //注意:不同的瀏覽器提交的文件名是不一樣的,有些瀏覽器提交上來的文件名是帶有路徑的,如:  c:\a\b\1.txt,而有些只是單純的文件名,如:1.txt
54                     //處理獲取到的上傳文件的文件名的路徑部分,只保留文件名部分
55                     filename = filename.substring(filename.lastIndexOf("\\") + 1);
56                     //獲取item輸入流
57                     InputStream inputStream = item.getInputStream();
58                     //創建一個文件輸出流
59                     FileOutputStream fileOutputStream  =new FileOutputStream(savePath+"\\"+filename);
60                     //創建一個緩沖區
61                     byte buffer[] = new byte[1024];
62                     //判斷輸入流是否已經讀完的標識
63                     int len = 0;
64                     while ((len=inputStream.read(buffer))>0)
65                     {
66                         fileOutputStream.write(buffer,0,len);
67                     }
68                     inputStream.close();
69                     fileOutputStream.close();
70                     item.delete();
71                     message = "文件上傳成功";
72 
73 
74 
75                 }
76             }
77         }catch (Exception e)
78         {
79             message = "文件上傳失敗";
80             e.printStackTrace();
81         }
82         req.setAttribute("message",message);
83         req.getRequestDispatcher("/message.jsp").forward(req,resp);
84     }
85 
86     @Override
87     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
88         doGet(req,resp);
89     }
90 }

 

    改進實現:

package com.qq.upload;



import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;
import java.util.UUID;

/**         上述的代碼雖然可以成功將文件上傳到服務器上面的指定目錄當中,但是文件上傳功能有許多需要注意的小細節問題,以下列出的幾點需要特別注意的
          1、為保證服務器安全,上傳文件應該放在外界無法直接訪問的目錄下,比如放於WEB-INF目錄下。
          2、為防止文件覆蓋的現象發生,要為上傳文件產生一個唯一的文件名。
          3、為防止一個目錄下面出現太多文件,要使用hash算法打散存儲。
          4、要限制上傳文件的最大值。
          5、要限制上傳文件的類型,在收到上傳文件名時,判斷后綴名是否合法。*/
@WebServlet("/doUpload2")
public class Upload2  extends HttpServlet {

    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //得到上傳文件的保存目錄,將上傳的文件存放在WEB-INF目錄下面 不允許外界直接訪問,保證上傳文件的安全
        String savePath = this.getServletContext().getRealPath("/LoadJsp");
        String tempPath = this.getServletContext().getRealPath("/LoadJsp/temp");
        File file  =new File(tempPath);
        if(!file.exists()&&!file.isDirectory()){
            System.out.println(tempPath+"目標目錄不存在,需要進行創建");
            file.mkdir();

        }
        String message = null;
        try {
            //1 創建DiskFileItemFactory工廠
            DiskFileItemFactory factory = new DiskFileItemFactory();
            //設置緩沖區得大小
            factory.setSizeThreshold(1024*1000000);
            //設置上傳時生成得臨時文件保存目錄
            factory.setRepository(file);
            //2 創建一個文件上傳解析器
            ServletFileUpload upload = new ServletFileUpload(factory);
            //監聽文件上傳速度
            upload.setProgressListener(new ProgressListener() {
                @Override
                public void update(long pBytesRead, long pContentLength, int arg2) {
                    System.out.println("文件大小為:" + pContentLength+"當前處理"+pBytesRead);
                }
            });
            //判斷提交上來的數據是不是表單上的數據
            upload.setHeaderEncoding("UTF-8");
            if (!ServletFileUpload.isMultipartContent(req)) {
                return;
            }
            //設置上傳文件總量得最大值
            upload.setSizeMax(1024*10*1024000);
            //設置單個上傳文件得最大值
            upload.setFileSizeMax(1024*1000000);

            //4 使用ServletFileUpload解析器來解析上傳數據,解析結果返回的是一個List<FileItem>
            //集合,每一個FileItem對應一個Form表單的輸入項
            List<FileItem> list = upload.parseRequest(req);
            for(FileItem item:list) {
                if (item.isFormField()) {
                    String name = item.getFieldName();
                    String value = item.getString("UTF-8");
                    System.out.println(name + "=" + value);
                } else {
                    String filename = item.getName();
                    System.out.println(filename);
                    if (filename == null || filename.trim().equals("")) {
                        continue;
                    }
                    //注意:不同的瀏覽器提交的文件名是不一樣的,有些瀏覽器提交上來的文件名是帶有路徑的,如:  c:\a\b\1.txt,而有些只是單純的文件名,如:1.txt
                    //處理獲取到的上傳文件的文件名的路徑部分,只保留文件名部分
                    filename = filename.substring(filename.lastIndexOf("\\") + 1);
                    //獲得文件擴展名字
                String    fileExname = filename.substring(filename.lastIndexOf(".")+1);
                    System.out.println("上傳的文件的擴展名是:"+fileExname);
                    //獲取item輸入流
                    InputStream inputStream = item.getInputStream();
                    //得到保存文件得名稱
                    String saveFilename  = makeFileName(filename);
                    //得到文件得保存目錄
                    String realSavaPath = makePath(saveFilename,savePath);
                    //創建一個文件輸出流

                    FileOutputStream fileOutputStream  =new FileOutputStream(realSavaPath
                            +"\\"+saveFilename);
                    //創建一個緩沖區
                    byte buffer[] = new byte[1024];
                    //判斷輸入流是否已經讀完的標識
                    int len = 0;
                    while ((len=inputStream.read(buffer))>0)
                    {
                        fileOutputStream.write(buffer,0,len);
                    }
                    inputStream.close();
                    fileOutputStream.close();
                   // item.delete();
                    message = "文件上傳成功";



                }
            }
        }catch (Exception e)
        {
            message = "文件上傳失敗";
            e.printStackTrace();
        }
        req.setAttribute("message",message);
        req.getRequestDispatcher("/message.jsp").forward(req,resp);
    }

    /**
     * @method:makeFileName
     * 生成上傳文件的文件名,文件名以:UUID標識符+"_"+文件的原始名稱
     * @param filename
     * @return
     */
    private String makeFileName(String filename)
    {
        //為防止文件覆蓋的現象發生,要為上傳文件產生一個唯一的文件名
        return UUID.randomUUID().toString()+"_"+filename;
    }

    /**
     * 為防止目錄下面出現太多文件,要使用hash算法打算存存儲
     * @param filename
     * @param savePath
     * @return
     */
    private String makePath(String filename,String savePath)
    {

        int hashcode = filename.hashCode();
        int dir1 = hashcode&0xf;//0--15
        /*int dir2 = (hashcode&0xf0)>>4;//0--15*/

        //構建新的保存目錄
        String dir   = savePath+"\\"+dir1;
        //File可以代表文件也可以代表目錄
        File file = new File(dir);
        if(!file.exists())
        {
            file.mkdir();
            System.out.println("創建新目錄成功!路徑地址為:"+dir);

        }
        return  dir;

    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

 

列出WEB系統中所有下載文件:
package com.qq.upload;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @BelongsPackage: com.qq.upload
 * @Author: ZHENGZHIQIANG
 * @CreateTime: 2019-03-18 11:16
 * @Description: 列出WEB系統中所有下載文件
 */
@WebServlet("/ListFileServlet")
public class ListFileServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //獲取上傳文件的目錄
        String uploadFilePath = this.getServletContext().getRealPath("/LoadJsp");
        //存儲要下載的文件名
        Map<String, String> fileNameMap = new HashMap<>();
        //遍歷filepath目錄下面的所有文件和目錄,將文件的文件名稱存儲到map中
        listfile(new File(uploadFilePath), fileNameMap);
        //將Map集合發送到listfile.jsp頁面進行顯示
        req.setAttribute("fileNameMap", fileNameMap);
        req.getRequestDispatcher("/listfile.jsp").forward(req, resp);
    }

    public void listfile(File file, Map<String, String> map) {
        if (!file.exists()) {
            File files[] = file.listFiles();
            //遍歷files數組
            for (File f : files) {
                listfile(f, map);
            }
        } else {
            /*
             處理文件名,上傳后的文件是以uuid_文件名的形式去重新命名的,去除文件名的uuid_部分
             file.getName().indexOf("_")檢索字符串中第一次出現"_"字符的位置,如果文件名類似於:9349249849-88343-8344_阿_凡_達.avi
             那么file.getName().substring(file.getName().indexOf("_")+1)處理之后就可以得到阿_凡_達.avi部分
             */
            String realName = file.getName().substring(file.getName().indexOf("_") + 1);
            //file.getName()得到的是文件的原始名稱,這個名稱是唯一的,因此可以作為key,realName是處理過后的名稱,有可能會重復
            map.put(file.getName(), realName);
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

 

 
        
實現文件下載功能:
package com.qq.upload;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;

/**
 * @Description: 實現文件下載功能
 * @Author: ZHENGZHIQIANG
 * @CreateTime: 2019-03-21 10:43
 */
public class DownLoadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //得到要下載的文件名稱
        String fileName =  req.getParameter("filename");
        fileName = new String(fileName.getBytes("iso8859-1"),"utf-8");
        //上傳文件都是保存在/web-inf/loadjsp目錄下的子目錄中
        String fileSaveRootPath = this.getServletContext().getRealPath("/LoadJsp");
        //通過文件名找到文件所在的目錄
        String path = findFileSavePathByFileName(fileName,fileSaveRootPath);
        //得到要下載的文件
        File file = new File(path+"\\"+fileName);
        if(!file.exists())
        {
            req.setAttribute("message","您要下載的資源不存在");
            req.getRequestDispatcher("/message.jsp").forward(req,resp);
            return;
        }
        //處理文件名稱
        String realName = fileName.substring(fileName.lastIndexOf("_")+1);
        //控制瀏覽器下載該文件
        resp.setHeader("content-disposition","attachment;filename="+URLEncoder.encode(realName,"UTF-8"));
        //讀取需要下載的文件 保存到文件輸入流
        FileInputStream fileInputStream = new FileInputStream(path+"//"+fileName);
        //創建輸出流
        OutputStream fileOutputStream = resp.getOutputStream();
        //創建緩沖區
        byte []buffer =new byte[1024];
        int len =0;
        while ((len = fileInputStream.read(buffer))>0)
        {
            fileOutputStream.write(buffer,0,len);
        }
        fileInputStream.close();
        fileOutputStream.close();
    }
        public String findFileSavePathByFileName(String filename,String saveRootPath)
        {
            int hashcode = filename.hashCode();
            int dir1 = hashcode&0xf;
            String dir  = saveRootPath+"//"+dir1;
            File file = new File(dir);
            if(!file.exists())
            {
                file.mkdir();
            }
            return dir;
        }


    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

 

 

效果如下:

JSP頁面代碼如下:

<%--
  Created by IntelliJ IDEA.
  User: ZHENGZHIQIANG
  Date: 2019/3/11
  Time: 11:36
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>File upload</title>
  </head>
  <body>
<form action="/doUpload2" enctype="multipart/form-data" method="POST">
         上傳用戶:<input type="text" name="username"><br/>
         上傳文件1:<input type="file" name="file1"><br/>
         上傳文件2:<input type="file" name="file2"><br/>
         <input type="submit" value="提交">
</form>
  </body>
</html>

**************
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
  Created by IntelliJ IDEA.
  User: ZHENGZHIQIANG
  Date: 2019/3/18
  Time: 11:52
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>下載文件顯示頁面</title>
</head>
<body>
<%--遍歷Map集合--%>
<c:forEach var="me" items="${fileNameMap}">
<c:url value="/ListFileServlet" var = "downurl">
    <c:param name="filename" value="${me.key}">
    </c:param>
</c:url>
    ${me.value}<a href="${downurl}">下載</a>
    <br/>
</c:forEach>

</body>
</html>
********************
<%--
  Created by IntelliJ IDEA.
  User: ZHENGZHIQIANG
  Date: 2019/3/13
  Time: 16:28
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Return message</title>
</head>
<body>
${message}
</body>
</html>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM