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内存流:java.io.ByteArrayInputStreamjava.io.ByteArrayOutputStreamjava.io.CharArrayReaderjava.io(代码片段
java缓冲字符字节输入输出流:java.io.BufferedReaderjava.io.BufferedWriterjava.io.BufferedInputStreamjava.io.(代码片段