JavaWeb IO流实现文件上传下载

Posted 余年庆庆余年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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>

 

以上是关于JavaWeb IO流实现文件上传下载的主要内容,如果未能解决你的问题,请参考以下文章

java web 大文件上传下载

java的纯JDBC能实现上传下载吗?怎么实现?

实现文件上传文件的地址的获取手段之一IO流读取

文件上传

java内存流:java.io.ByteArrayInputStreamjava.io.ByteArrayOutputStreamjava.io.CharArrayReaderjava.io(代码片段

java缓冲字符字节输入输出流:java.io.BufferedReaderjava.io.BufferedWriterjava.io.BufferedInputStreamjava.io.(代码片段