文件上传简介:
1.文件上传浏览器端
1.method=post 只有post才可以携带大数据 2.必须使用<input type='file' name='f'>要有name属性 3.encType="multipart/form-data"
2.文件上传服务器端:request对象用于获取请求信息。有一个方法 getInputStream(); 可以获取一个字节输入流,通过这个流,可以读取到所有的请求正文信息。
2.1 upload1.jsp
html> <head> <title>My JSP 'index.jsp' starting page</title> </head> <body> <form action="${pageContext.request.contextPath}/upload1" method="post" encType="multipart/form-data"> <input type="text" name="content"><br> <input type="file" name="f"><br> <input type="submit" value="上传"> </form> </body> </html>
页面示例:
2.2 Upload1Servlet.java
import java.io.IOException; import java.io.InputStream; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Upload1Servlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //通过request获取一个字节输入流,将所有的请求正文信息读取到,打印到控制台。 InputStream is=request.getInputStream(); byte[] b=new byte[1024]; int len=-1; while((len=is.read(b))!=-1){ System.out.print(new String(b,0,len)); } is.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
2.3 测试结果
3.文件上传原理:浏览器端注意上述三件事,在服务器端通过流将数据读取到,在对数据进行解析.将上传文件内容得到,保存在服务器端,就完成了文件上传。在实际开发中,不需要我们进行数据解析,完成文件上传。因为我们会使用文件上传的工具(commons-fileupload),它们已经封装好的,提供API,只要调用它们的API就可以完成文件上传操作。
文件上传工具:commons-fileupload
1.核心类介绍
commons-fileupload-1.2.1.jar 文件上传commons-io-1.4.jar 它是提供的io工具. 它有三个核心:1.DiskFileItmeFactory类 2.ServletFileUpload类 3.FilteItem 1.DiskFileItemFactory作用:可以设置缓存大小以及临时文件保存位置.默认缓存大小是 10240(10k). 临时文件默认存储在系统的临时文件目录下.(可以在环境变量中查看) new DiskFileItemFactory(); 缓存大小与临时文件存储位置使用默认的. DiskFileItemFactory(int sizeThreshold, File repository) sizeThreshold :缓存大小 repository:临时文件存储位置 注意,对于无参数构造,也可以设置缓存大小以及临时文件存储位置. setSizeThreshold(int sizeThreshold) setRepository(File repository) 2.ServletFileUpload ServletFileUpload upload=new ServletFileUpload(factory); 创建一个上传工具,指定使用缓存区与临时文件存储位置. List<FileItem> items=upload.parseRequest(request); 它是用于解析request对象,得到所有上传项.每一个FileItem就相当于一个上传项. boolean flag=upload.isMultipartContent(request); 用于判断是否是上传. 可以简单理解,就是判断encType="multipart/form-data"; 设置上传文件大小 void setFileSizeMax(long fileSizeMax) 设置单个文件上传大小 void setSizeMax(long sizeMax) 设置总文件上传大小 解决上传文件中文名称乱码 setHeaderEncoding("utf-8"); 注意:如果使用reqeust.setCharacterEncoding("utf-8")也可以,但不建议使用。 3.FileItem 3.1.isFormField 用于判断是否是上传组件.如果是<input type="file">返回的就是false,否则返回true. 3.2.getFieldName(); 返回值String,得到组件名称 <input name=""> 3.3.getName(); 返回值是String,得到的是上传文件的名称. 注意:浏览器不同,它们得到的效果不一样。 1.包含全路径名称 例如: C:UsersAdministratorDesktopa.txt 2.只包含上传文件名称 例如:a.txt 3.4.getString(); 这个方法可以获取非上传组件的内容,相当于 getParameter方法作用。 问题:如果信息是中文,会出现乱码,解决方案 getString("utf-8"); 如果是上传组件,上传的文件是文本文件,可以获取到文件文件的内容。 但是如果不是文件文件,例如:是一张图片,这样获取合适吗? 3.5.获取上传文件的内容,保存到服务器端. item.getInputStream();它是用于读取上传文件内容的输入流. 使用文件复制操作就可以完成文件上传。 3.6.删除临时文件 item.delete(); 总结:关于文件上传时的乱码问题: 1.上传文件名称乱码 ServletFileUpload.setHeaderEncoding("utf-8"); 2.非上传组件内容乱码 FileItem.getString("utf-8"); 3.思考:上传文件信息是否会乱码,需要解决吗? 不需要解决,因为我们在上传时,使用的字节流来进行复制。
2.文件上传注意事项
1.上传文件在服务器端保存位置问题 1.1.保存在可以被浏览器直接访问的位置 例如:商城的商品图片 保存在工程的WebRoot下的路径(不包含META-INF以及WEB-INF目录及其子目录) 1.2.保存在不能被浏览器直接访问的位置 例如:付费的视频。 1).工程中META-INF WEB-INF目录及其子目录 2).不在工程中的服务器的磁盘目录下. 2.上传文件在同一个目录重名问题 在开发中解决这个问题,可以给上传文件起随机名称。 1).使用毫秒值 2).使用uuid 3.同一目录下文件过多只需要分目录就可以. 1) 按照上传时间进行目录分离 (周、月 ) 2) 按照上传用户进行目录分离 ----- 为每个用户建立单独目录 3) 按照固定数量进行目录分离 ------ 假设每个目录只能存放3000个文件 ,每当一个目录存满3000个文件后,创建一个新的目录 4)按照文件名的hashcode进行目录分离. public static String generateRandomDir(String uuidFileName) { // 获得唯一文件名的hashcode int hashcode = uuidFileName.hashCode(); // 获得一级目录 int d1 = hashcode & 0xf; // 获得二级目录 int d2 = (hashcode >>> 4) & 0xf; return "/" + d2 + "/" + d1;// 共有256目录l }
3.多文件上传实例
3.1 上传页面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>多文件上传</title> <script type="text/javascript"> function addFile(){ var div=document.getElementById("content"); div.innerHTML+="<div><input type='file' name='f'><input type='button' value='remove file' onclick='removeFile(this)'></div>"; } function removeFile(btn){ document.getElementById("content").removeChild(btn.parentNode); } </script> </head> <body> <input type="button" value="add File" onclick="addFile();"> <br> <br> <form action="${pageContext.request.contextPath}/upload4" method="post" encType="multipart/form-data"> <input type="file" name="f"><br> <div id="content"> </div> <input type="submit" value="上传"> </form> </body> </html>
页面示例
3.2 Upload4Servlet.java
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.List; import javax.servlet.ServletException; 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; import org.apache.commons.io.IOUtils; import cn.itcast.utils.FileUploadUtils; public class Upload4Servlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); // 1.创建 DiskFileItemFactory File file = new File(this.getServletContext().getRealPath("/temp"));// 获取temp目录部署到tomcat后的绝对磁盘路径 DiskFileItemFactory factory = new DiskFileItemFactory(1024 * 100, file); // 使用默认的. // 2.创建ServletFileUpload ServletFileUpload upload = new ServletFileUpload(factory); boolean flag = upload.isMultipartContent(request); // 用于判断是否是上传操作. if (flag) { // 解决上传文件名称中文乱码 upload.setHeaderEncoding("utf-8"); // 设置上传文件大小 // upload.setSizeMax(1024 * 1024 * 10);// 总大小为10m try { List<FileItem> items = upload.parseRequest(request);// 解决request,得到所有的上传项FileItem // 3.得到所有上传项 for (FileItem item : items) { if (!item.isFormField()) { // item.isFormField()得到了<input type="text" name="content">这样的组件 /*String fieldName = item.getFieldName(); String name = item.getName(); String msg = item.getString(); */ // !item.isFormField()就是<input type="file"> 这样的上传组件 String name = item.getName(); // 上传文件名称 // 得到上传文件真实名称 String filename = FileUploadUtils.getRealName(name); // 得到随机名称 String uuidname = FileUploadUtils.getUUIDFileName(filename); // 得到随机目录 String randomDirectory = FileUploadUtils.getRandomDirectory(filename); // 注意:随机目录可能不存在,需要创建. String parentPath = this.getServletContext().getRealPath("/upload"); File rd = new File(parentPath, randomDirectory); if (!rd.exists()) { rd.mkdirs(); } IOUtils.copy(item.getInputStream(),new FileOutputStream(new File(rd, uuidname))); // 删除临时文件 item.delete(); } } } catch (FileUploadException e) { // e.printStackTrace(); response.getWriter().write(e.getMessage()); return; } } else { response.getWriter().write("不是上传操作"); return; } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
3.3 上传辅助类 FileUploadUtils.java
import java.io.File; import java.util.UUID; public class FileUploadUtils { // 得到上传文件真实名称 c:a.txt a.txt public static String getRealName(String filename) { int index = filename.lastIndexOf("\") + 1; return filename.substring(index); } // 获取随机名称 a.txt public static String getUUIDFileName(String filename) { int index = filename.lastIndexOf("."); if (index != -1) { return UUID.randomUUID() + filename.substring(index); } else { return UUID.randomUUID().toString(); } } // 目录分离算法 public static String getRandomDirectory(String filename) { // int hashcode = filename.hashCode(); // // // System.out.println(hashcode); // // // int类型数据在内存中占32位。转换成16进制数,就得到8个16进制数 // String hex = Integer.toHexString(hashcode); // // // System.out.println(hex); // 056d9363 // // return "/" + hex.charAt(0) + "/" + hex.charAt(1); int hashcode = filename.hashCode(); System.out.println(Integer.toBinaryString(hashcode)); int a = hashcode & 0xf; hashcode = hashcode >>> 4; int b = hashcode & 0xf; return "/" + a + "/" + b; } }
3.4 上传结果
文件下载:
文件下载的方式:
1.超连接下载
download1.jsp <a href='${pageContext.request.contextPath}/upload/a.bmp'>a.bmp</a><br> <a href='${pageContext.request.contextPath}/upload/a.doc'>a.doc</a><br> <a href='${pageContext.request.contextPath}/upload/a.txt'>a.txt</a><br> <a href='${pageContext.request.contextPath}/upload/tk.mp3'>tk.mp3</a><br> 注意:如果文件可以直接被浏览器解析,那么会在浏览器中直接打开,不能被浏览器直接解析,就是下载操作。 直接打开的要想下载 ,右键另存为。 超连接下载,要求下载 的资源,必须是可以直接被浏览器直接访问的。 客户端访问服务器静态资源文件时,静态资源文件是通过 缺省Servlet返回的, 在tomcat配置文件conf/web.xml 找到 --- org.apache.catalina.servlets.DefaultServlet
2.服务器端通过流下载(服务器端编程)
1.创建download2.jsp <a href='${pageContext.request.contextPath}/download?filename=a.bmp'>a.bmp</a><br> <a href='${pageContext.request.contextPath}/download?filename=a.doc'>a.doc</a><br> <a href='${pageContext.request.contextPath}/download?filename=a.txt'>a.txt</a><br> <a href='${pageContext.request.contextPath}/download?filename=tk.mp3'>tk.mp3</a><br> 2.创建DownloadServlet // 1.得到要下载 的文件名称 String filename = request.getParameter("filename"); //2.判断文件是否存在 File file = new File("d:/upload/" + filename); if (file.exists()) //3.进行下载 原理:就是通过response获取一个输出流,将要下载的文件内容写回到浏览器端就可以了. 注意:要想通过编程的方式,实现文件下载, 1.要设置mimetype类型 resposne.setContextType(String mimeType); 问题:怎样可以得到要下载文件的mimeType类型? ServletContext.getMimeType(String filename); 如果设置了mimeType,浏览器能解析的就直接展示了,不能解析的,直接下载. 2.设置一个响应头,设置后的效果,就是无论返回的是否可以被浏览器解析,就是下载 。 response.setHeader("content-disposition","attachment;filename=下载文件名称"); 总结:服务器端编程下载: 1.将下载的文件通过resposne.getOutputStream()流写回到浏览器端。 2.设置mimeType response.setContentType(getServletContext.getMimeType(String filename)); 3.设置响应头,目的是永远是下载操作 response.setHeader("content-disposition","attachment;filename=下载文件名称");
3.文件下载时的乱码问题
1.关于下载时中文名称资源查找不到 原因:<a href='${pageContext.request.contextPath}/download?filename=天空.mp3'>天空.mp3</a> 这是get请求。 在服务器端: String filename = request.getParameter("filename"); 解决: new String(filename.getBytes("iso8859-1"),"utf-8"); 2.下载文件显示时的中文乱码问题 response.setHeader("content-disposition", "attachment;filename="+filename); IE:要求filename必须是utf-8码 firefox:要求filename必须是base64编码. 问题:怎样判断浏览器? String agent=request.getHeader("user-agent"); if (agent.contains("MSIE")) { // IE浏览器 filename = URLEncoder.encode(filename, "utf-8"); } else if (agent.contains("Firefox")) { // 火狐浏览器 BASE64Encoder base64Encoder = new BASE64Encoder(); filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?="; }else { // 其它浏览器 filename = URLEncoder.encode(filename, "utf-8"); }
附件:文件上传和下载源码 密码:dpsu;