5.servlet 上传文件
一.maven依赖
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency>
二.DiskFileItemFactory类的使用
将请求消息实体中的每一个项目封装成单独的DiskFileItem (FileItem接口的实现) 对象的任务
由 org.apache.commons.fileupload.FileItemFactory 接口的默认实现
org.apache.commons.fileupload.disk.DiskFileItemFactory 来完成。当上传的文件项目比较小时,直接保存在内存中(速度比较快),比较大时,以临时文件的形式,保存在磁盘临时文件夹(虽然速度慢些,但是内存资源是有限的)。
属性
1) public static final int DEFAULT_SIZE_THRESHOLD :将文件保存在内存还是磁盘临时文件夹的默认临界值,值为10240,即10kb。
2) private File repository:用于配置在创建文件项目时,当文件项目大于临界值时使用的临时文件夹,默认采用系统默认的临时文件路径,可以通过系统属性 java.io.tmpdir获取。如下代码:
System.getProperty("java.io.tmpdir");
3) private int sizeThreshold:用于保存将文件保存在内存还是磁盘临时文件夹的临界值
构造方法
1) public DiskFileItemFactory()
采用默认临界值和系统临时文件夹构造文件项工厂对象。
2) public DiskFileItemFactory(int sizeThreshold,File repository)
采用参数指定临界值和系统临时文件夹构造文件项工厂对象。
3) FileItem createItem()
根据DiskFileItemFactory相关配置将每一个请求消息实体项目创建成DiskFileItem 实例,并返回。该方法从来不需要我们亲自调用,FileUpload组件在解析请求时内部使用。
4) void setSizeThreshold(int sizeThreshold)
Apache文件上传组件在解析上传数据中的每个字段内容时,需要临时保存解析出的数据,以便在后面进行数据的进一步处理(保存在磁盘特定位置或插入数据库)。因为Java虚拟机默认可以使用的内存空间是有限的,超出限制时将会抛出“java.lang.OutOfMemoryError”错误。如果上传的文件很大,例如800M的文件,在内存中将无法临时保存该文件内容,Apache文件上传组件转而采用临时文件来保存这些数据;但如果上传的文件很小,例如600个字节的文件,显然将其直接保存在内存中性能会更加好些。
setSizeThreshold方法用于设置是否将上传文件已临时文件的形式保存在磁盘的临界值(以字节为单位的int值),如果从没有调用该方法设置此临界值,将会采用系统默认值10KB。对应的getSizeThreshold() 方法用来获取此临界值。
5) void setRepository(File repository)
setRepositoryPath方法用于设置当上传文件尺寸大于setSizeThreshold方法设置的临界值时,将文件以临时文件形式保存在磁盘上的存放目录。有一个对应的获得临时文件夹的 File getRespository() 方法。
注意:当从没有调用此方法设置临时文件存储目录时,默认采用系统默认的临时文件路径,可以通过系统属性 java.io.tmpdir 获取。如下代码:
System.getProperty("java.io.tmpdir");
Tomcat系统默认临时目录为“<tomcat安装目录>/temp/”。
三.使用Commons-Fileupload包进行大文件上传注意事项
项目中使用
commons-fileupload-1.2.1.jar
进行大文件上传。
测试了一把,效果很不错。
总结如下:
-
必须设置好上传文件的最大阀值
final long MAX_SIZE = 10 * 1024 * 1024 * 1024;// 设置上传文件最大为 10G
-
必须设置文件上传服务器上的临时目录
// 文件上传参数配置
// 创建一个新的文件上传句柄
DiskFileItemFactory factory = new DiskFileItemFactory();
// 设置内存缓冲区,超过后写入临时文件
factory.setSizeThreshold(4096);
// 设置上传到服务器上文件的临时存放目录 -- 非常重要,防止存放到系统盘造成系统盘空间不足
factory.setRepository(new File("F:\\uploadFileTemp"));
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("utf-8");
// 设置单个文件的最大上传值
upload.setSizeMax(MAX_SIZE); // 文件上传上限10G -
上传成功后一定要删除临时目录的临时文件
fileItem.delete(); // 请务必调用,在文件上传结束后,删除临时目录的文件...
-
最好记录下文件从开始上传到上传结束的时间点,这个对今后文件上传时间的分析很有用
另外,因为Struts2的上传功能也引入了该包,但是却做了拦截器限制文件的最大上传大小为2M,可以通过修改它的配置文件动态更改上传文件的大小;而且,Struts会在文件上传成功后,帮你删除掉临时文件。
我这里使用的是Spring MVC,需要在上传类中指定最大上传文件大小,(这玩意一般不动态设置,最大上传文件大小一般是系统的标准,是让使用者遵循滴),而且必须在上传成功后删除临时文件。
四.示例代码
1)JSP界面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <form action="UploadFile" method="post" enctype="multipart/form-data" multiple> <input type="file" name="myFile" size="10" > <input type="submit" value="上传文件"> </form> </body> </html>
2)servlet处理代码
package com.my.web; import java.io.File; import java.io.IOException; import java.util.Iterator; import java.util.List; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.annotation.WebInitParam; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; /** * Servlet implementation class UploadFile */ @WebServlet(name = "UploadFile", urlPatterns = { "/UploadFile" }, initParams = { @WebInitParam(name = "filepath", value = "D:/Tools/sandbox/data/") }) public class UploadFile extends HttpServlet { private static final long serialVersionUID = 1L; private int maxFileSize = 50 * 1024; private int maxMemSize = 4 * 1024; private boolean isMultipart; private String filePath; private File file; /** * @see HttpServlet#HttpServlet() */ public UploadFile() { super(); // TODO Auto-generated constructor stub } /** * @see Servlet#init(ServletConfig) */ public void init(ServletConfig config) throws ServletException { // TODO Auto-generated method stub filePath = config.getInitParameter("filepath").toString(); System.out.println(filePath); } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse * response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub // 用于判断是普通表单,还是带文件上传的表单 isMultipart = ServletFileUpload.isMultipartContent(request); response.setContentType("text/html; charset=UTF-8"); DiskFileItemFactory factory = new DiskFileItemFactory(); factory.setSizeThreshold(maxMemSize); // Location to save data that is larger than maxMemSize. factory.setRepository(new File("D:\\Tools\\sandbox\\temp")); // 创建一个新的文件上传处理程序 ServletFileUpload upload = new ServletFileUpload(factory); upload.setHeaderEncoding("UTF-8"); //允许上传的文件大小的最大值 upload.setSizeMax(maxFileSize); try { // 解析请求,获取文件项 List<FileItem> fileItems = upload.parseRequest(request); // 处理上传的文件项 Iterator i = fileItems.iterator(); while ( i.hasNext () ) { FileItem fi = (FileItem)i.next(); if ( !fi.isFormField () ) { // 获取上传文件的参数 String fieldName = fi.getFieldName(); String fileName = fi.getName(); String contentType = fi.getContentType(); boolean isInMemory = fi.isInMemory(); long sizeInBytes = fi.getSize(); // 写入文件 if( fileName.lastIndexOf("\\") >= 0 ){ file = new File( filePath + fileName.substring( fileName.lastIndexOf("\\"))) ; }else{ file = new File( filePath + fileName.substring(fileName.lastIndexOf("\\")+1)) ; } fi.write( file ) ; } } } catch (FileUploadException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } response.getWriter().append("Served at: ").append(String.valueOf(isMultipart)); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse * response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } }
或者
package com.my.web; import java.io.File; import java.io.IOException; import java.util.Iterator; import java.util.List; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.annotation.WebInitParam; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; /** * Servlet implementation class UploadFile */ @WebServlet(name = "UploadFile2", urlPatterns = { "/UploadFile2" }, initParams = { @WebInitParam(name = "filepath", value = "D:/Tools/sandbox/data/") }) public class UploadFile2 extends HttpServlet { private static final long serialVersionUID = 1L; private int maxFileSize = 50 * 1024; private int maxMemSize = 4 * 1024; private boolean isMultipart; private String filePath; private File file; /** * @see HttpServlet#HttpServlet() */ public UploadFile2() { super(); // TODO Auto-generated constructor stub } /** * @see Servlet#init(ServletConfig) */ public void init(ServletConfig config) throws ServletException { // TODO Auto-generated method stub filePath = config.getInitParameter("filepath").toString(); System.out.println(filePath); } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse * response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub // 用于判断是普通表单,还是带文件上传的表单 isMultipart = ServletFileUpload.isMultipartContent(request); response.setContentType("text/html; charset=UTF-8"); DiskFileItemFactory factory = new DiskFileItemFactory(); factory.setSizeThreshold(maxMemSize); // Location to save data that is larger than maxMemSize. factory.setRepository(new File("D:\\Tools\\sandbox\\temp")); // 创建一个新的文件上传处理程序 ServletFileUpload upload = new ServletFileUpload(factory); upload.setHeaderEncoding("UTF-8"); //允许上传的文件大小的最大值 upload.setSizeMax(maxFileSize); try { // 解析请求,获取文件项 List<FileItem> fileItems = upload.parseRequest(request); for (FileItem item : fileItems) { if(item.isFormField()){ String name = item.getFieldName(); //解决普通输入项的数据的中文乱码问题 String value = item.getString("UTF-8"); //value = new String(value.getBytes("iso8859-1"),"UTF-8"); System.out.println(name + "=" + value); }else{//如果fileitem中封装的是上传文件 //得到上传的文件名称, 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 fileExtName = filename.substring(filename.lastIndexOf(".")+1); filename = filename.substring(0,filename.lastIndexOf(".")); //如果需要限制上传的文件类型,那么可以通过文件的扩展名来判断上传的文件类型是否合法 System.out.println("上传的文件的扩展名是:"+fileExtName); //保存文件 file = new File( filePath + filename +"." + fileExtName); item.write(file); } } } catch (FileUploadException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } request.getRequestDispatcher("/uploadFile.jsp").forward(request, response); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse * response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } }