10.Java文件传输

一.文件上传和下载

1.准备工作

  • 搭建maven-archetype-webapp项目,导入jar包

 1 <dependencies>
 2     <dependency>
 3         <groupId>commons-io</groupId>
 4         <artifactId>commons-io</artifactId>
 5         <version>2.6</version>
 6     </dependency>
 7 
 8     <dependency>
 9         <groupId>commons-fileupload</groupId>
10         <artifactId>commons-fileupload</artifactId>
11         <version>1.4</version>
12     </dependency>
13 
14 </dependencies>

2.注意事项

  1. 为了保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放在WEB-INF目录下

  2. 为防止文件覆盖现象发生,要为上传文件产生一个唯一的文件名。(使用UUID,md5,位运算算法)

  3. 要限制上传文件的最大值

  4. 可以限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法

3.需要用到的类详解

  ServletFileUpload负责处理上传的文件数据,并将表单中每个输入项封装成一个FileItem对象,在使用ServletFileUpload对象解析请求时需要DiskFileItemFactory对象。所以,我们需要在进行解析工作前构造好DisFileItemFactory对象,通过ServletFileUpload对象的构造方法或setFileItemFactory()方法设置ServletFileUpload对象的fileItemFactory属性。

(1)FileItem类

在HTML页面input必须有name  <input type="file" name="file1"> 

表单中如果包含一个文件上传输入项的话,这个表单的enctype属性就必须设置为multipart/form-data

 1 <%--
 2 通过表单上传文件
 3     get:上传文件大小有限制
 4     post:上传文件大小无限制
 5 
 6 ${pageContext.request.contextPath}获取服务器路径
 7 --%>
 8 <form action="${pageContext.request.contextPath}/upload.do" enctype="multipart/form-data" method="post">
 9     上传用户:<input type="text" name="username"> <br>
10     <p><input type="file" name="file1"></p>
11     <p><input type="file" name="file1"></p>
12     <p><input type="submit" value="提交"> | <input type="reset" value="重置">  </p>
13 </form>

注意:表单提交方式为post不限制上传大小,表单类型: enctype="multipart/form-data" 

(2)常用方法:

4.ServletFileUpload类

ServletFileUpload负责处理上传的数据,并将表单中每个输入项封装成一个FileItem对象中,使用其parseRequest(HttpServletRequest)方法可以讲通过表单中每一个HTML标签提交的数据封装成一个FileItem对象,然后以List列表的形式返回。使用该方法处理上传文件简单易用。

5.文件上传程序:

index.jsp:

 1 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 2 <html>
 3 <head>
 4     <title>index</title>
 5 </head>
 6 <body>
 7 
 8 <%--
 9 通过表单上传文件
10     get:上传文件大小有限制
11     post:上传文件大小无限制
12 
13 ${pageContext.request.contextPath}获取服务器路径
14 --%>
15 <form action="${pageContext.request.contextPath}/upload.do" enctype="multipart/form-data" method="post">
16     上传用户:<input type="text" name="username"> <br>
17     <p><input type="file" name="file1"></p>
18     <p><input type="file" name="file1"></p>
19     <p><input type="submit" value="提交"> | <input type="reset" value="重置">  </p>
20 </form>
21 
22 
23 </body>
24 </html>

FileServlet.java:

  1 import org.apache.commons.fileupload.FileItem;
  2 import org.apache.commons.fileupload.FileUploadException;
  3 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
  4 import org.apache.commons.fileupload.servlet.ServletFileUpload;
  5 
  6 import javax.servlet.ServletException;
  7 import javax.servlet.http.HttpServlet;
  8 import javax.servlet.http.HttpServletRequest;
  9 import javax.servlet.http.HttpServletResponse;
 10 import java.io.*;
 11 import java.util.List;
 12 import java.util.UUID;
 13 
 14 public class FileServlet extends HttpServlet {
 15     @Override
 16     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 17 
 18 
 19         //判断上传的文件是普通表单还是带文件的表单
 20         if (!ServletFileUpload.isMultipartContent(req)) {
 21             return; //普通表单直接返回
 22         }
 23 
 24         //创建上传文件的保存路径,建议在WEB-INF路径下,安全,用户无法直接访问上传的文件
 25         String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
 26         File uploadFile = new File(uploadPath);
 27         if (!uploadFile.exists()) {
 28             uploadFile.mkdir(); //没有目录创建目录
 29         }
 30 
 31         //缓存,临时文件
 32         //临时路径,加入文件超过了预期的大小,我们就把它放在一个临时文件中,过几天自动删除,或者提醒用户转存为永久
 33         String tmpPath = this.getServletContext().getRealPath("/WEB-INF/tmp");
 34         File tmpFile = new File(tmpPath);
 35         if (!tmpFile.exists()) {
 36             tmpFile.mkdir(); //没有临时目录创建目录
 37         }
 38 
 39         //处理上传文件,一般都需要通过流来获取,我们可以使用request.getInputStream(),原生态的文件上传流获取,十分麻烦
 40         //但是我们都建议使用Apache的文件上传组件来实现,common-fileupload,它依赖于common-io组件
 41         try {
 42             //1.创建DiskFileItemFactory对象,设置文件上传路径和文件大小限制
 43             DiskFileItemFactory factory = getDiskFileItemFactory(tmpFile);
 44 
 45             //2.获取ServletFileUpload
 46             ServletFileUpload upload = getServletFileUpload(factory);
 47 
 48             //3.处理上传文件
 49             String msg = uploadParseRequest(upload, req, uploadPath);
 50 
 51             //Servlet请求转发消息
 52             req.setAttribute("msg", msg);
 53             req.getRequestDispatcher("info.jsp").forward(req, resp);
 54 
 55         } catch (FileUploadException e) {
 56             e.printStackTrace();
 57         }
 58 
 59     }
 60 
 61     public static DiskFileItemFactory getDiskFileItemFactory(File file) {
 62         DiskFileItemFactory factory = new DiskFileItemFactory();
 63         //通过这个工厂设置一个缓存区,当上传的文件大于这个缓冲区的时候,将它放到临时文件中
 64         factory.setSizeThreshold(1024 * 1024);  //设置缓冲区大小1M
 65         factory.setRepository(file);            //设置临时文件目录
 66         return factory;
 67     }
 68 
 69     public static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory) {
 70         ServletFileUpload upload = new ServletFileUpload(factory);
 71 
 72         //监听文件上传的进度
 73         //pBytesRead:已经读取到的文件大小
 74         //pContentLength:文件大小
 75         upload.setProgressListener((pBytesRead, pContentLength, pItems) -> System.out.println("总大小:" + pContentLength + "已上传:" + pBytesRead));
 76 
 77         //处理乱码问题
 78         upload.setHeaderEncoding("UTF-8");
 79 
 80         //设置单个文件的最大值 10M
 81         upload.setFileSizeMax(1024 * 1024 * 10);
 82 
 83         //设置总共能够上传文件的大小 10M
 84         upload.setSizeMax(1024 * 1024 * 10);
 85 
 86         return upload;
 87     }
 88 
 89     public static String uploadParseRequest(ServletFileUpload upload, HttpServletRequest req, String uploadPath) throws FileUploadException {
 90 
 91         String msg = new String();
 92 
 93         try {
 94             //把前端请求解析,封装成一个FileItem对象,需要从ServletFileUpload对象中获取
 95             List<FileItem> fileItems = upload.parseRequest(req);
 96 
 97             //处理每一个表单对象
 98             for (FileItem fileItem : fileItems) {
 99                 //判断上传的文件是普通的表单还是带文件的表单
100                 if (fileItem.isFormField()) {
101                     //普通表单
102                     //getFileName指的是前端表单控件的name
103                     String name = fileItem.getFieldName();
104                     String value = fileItem.getString("UTF-8");
105                     System.out.println(name + ":" + value);
106                 } else {
107                     //文件
108                     //1.处理文件
109                     String uploadFileName = fileItem.getName();
110                     //处理文件名不合法的情况
111                     if (uploadFileName.trim().equals("") || uploadFileName == null) {
112                         continue;
113                     }
114                     //获得上传文件名 /images/girl/paojie.png
115                     String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);
116                     //获得文件后缀名
117                     String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);
118                     /*
119                         如果文件后缀名fileExtName 不是我们所需要的就直接return不处理,并告诉用户文件类型不正确
120                     */
121 
122                     System.out.println("文件信息 [文件名:" + fileName + "---文件类型:" + fileExtName + "]");
123 
124                     //可以使用UUID来保证文件名唯一
125                     //UUID.randomUUID(),随机生成一个唯一识别的通用码:
126                     String uuidPath = UUID.randomUUID().toString();
127 
128                     //对于我们创建的pojo实体类,如果想要在多台电脑上运行在网络上传输都要实现序列化接口
129                     //implement Serializable
130 
131                     //2.存放地址
132                     //生成文件真实存放地址
133                     String realPath = uploadPath + "/" + uuidPath;
134                     //给每一个文件创建一个文件夹
135                     File realPathFile = new File(realPath);
136                     if (!realPathFile.exists()) {
137                         realPathFile.mkdir();
138                     }
139 
140                     //3.文件传输
141                     //获得文件上传流
142                     InputStream inputStream = fileItem.getInputStream();
143 
144                     //创建一个文件输出流
145                     FileOutputStream fos = new FileOutputStream(realPath + "/" + fileName);
146 
147                     //创建一个缓冲区
148                     byte[] buffer = new byte[1024 * 1024];
149 
150                     //判断是否读取完毕
151                     int len = 0;
152                     //如果大于0说明还存在数据
153                     while ((len = inputStream.read(buffer)) > 0) {
154                         fos.write(buffer, 0, len);
155                     }
156 
157                     //关闭流
158                     fos.close();
159                     inputStream.close();
160 
161                     msg = "文件上传成功!";
162                     fileItem.delete();//上传成功,清除临时文件
163                 }
164             }
165         } catch (IOException e) {
166             e.printStackTrace();
167         }
168 
169         return msg;
170     }
171 }

web.xml注册:

 1 <!--注册Servlet-->
 2 <servlet>
 3   <servlet-name>FileServlet</servlet-name>
 4   <servlet-class>wzh.servlet.FileServlet</servlet-class>
 5 </servlet>
 6 
 7 <!--Servlet的请求路径-->
 8 <servlet-mapping>
 9   <servlet-name>FileServlet</servlet-name>
10   <url-pattern>/upload.do</url-pattern>
11 </servlet-mapping>

info.jsp:

 1 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 2 <html>
 3 <head>
 4     <title>info</title>
 5 </head>
 6 <body>
 7 
 8 ${msg}
 9 </body>
10 </html>

上传成功后保存路径:里面有tmp和upload目录

6.总结

主要理解思路和流程,其次才是调用的api和代码

原文地址:https://www.cnblogs.com/zhihaospace/p/12317721.html