文件上传的时要注意的是 form 表单必须是 method = "post" enctype = “multipart/form-data”
<form action="FileUpload" method="post" enctype="multipart/form-data"> file : <input type="file" name="file"/><br> <input type="submit" value="submit"> </form>
借助第三方库 (commons-fileupload) ,commons-fileupload 依赖 commons-io
Servlet 代码:FileUpload
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 检查一个请求是否是一个文件上传的请求 if(ServletFileUpload.isMultipartContent(request)){ // 创建一个基于磁盘文件条目的工厂 DiskFileItemFactory factory = new DiskFileItemFactory(); // 分别指定缓存文件路径和文件上传的目录 String tempPath = getServletContext().getRealPath("temp"); String filePath = getServletContext().getRealPath("file"); // 你也可以给这个工厂添加一些约束 // 超过设置的值会写到给出的磁盘目录中 factory.setSizeThreshold(1024*1024); factory.setRepository(new File(tempPath)); // 或者直接使用这个构造方法 // DiskFileItemFactory factory1 = new DiskFileItemFactory(1024*1024, new File("temp")); // 创建了个文件上传的处理 ServletFileUpload upload = new ServletFileUpload(factory); upload.setFileSizeMax(1024*1024*10); try { // 解释请求, 得到一个文件条目的List @SuppressWarnings("unchecked") List<FileItem> items = upload.parseRequest(request); for(FileItem item : items){ // 判断一个条目是否是一个普通的字段域 if(item.isFormField()){ /* * 对提交过来的表单中普通的参数进行处理 * name 是参数名 * value 是参数的值 */ String name = item.getFieldName(); String value = item.getString(); }else{ /* * 对文件进行相关的操作 */ String fieldName = item.getFieldName(); String fileName = item.getName(); String contentType = item.getContentType(); boolean isInMemory = item.isInMemory(); long sizeInByte = item.getSize(); // ... ... // 把文件写入到磁盘 item.write(new File(filePath, fileName)); } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
把大的文件一直存放在内存里面是不现实的。所以可以看到下面的这段代码
factory.setSizeThreshold(1024*1024);
这样当你上传的文件超过这个设置的值的大小 ,文件会被写到磁盘上的一个临时文件里面,之后又会被 org.apache.commons.io.FileCleaner这个类自动的清理掉。FileCleaner 会开启一个回收的线程。
如果不再使用这个使用的时候,应该要停止这个线程。比如 web应用程序结束的时候(停止Tomcat时。org.apache.commons.fileupload.servlet.FileCleanerCleanup 会停止掉这个临时文件清理线程。这时需要配制一个监听器,在web-app里加上配制文件:
<listener> <listener-class> org.apache.commons.fileupload.servlet.FileCleanerCleanup </listener-class> </listener>
或者你也可使用 FileCleanerCleanup 提供一个 org.apache.commons.io.FileCleaningTracker 实例来进行清理临时文件。在构建DiskFileItemFactory 时可以加上这样的代码。
FileCleaningTracker fileCleaningTracker = FileCleanerCleanup.getFileCleaningTracker(getServletContext()); factory.setFileCleaningTracker(fileCleaningTracker);
Item有一个简单的方法可以把文件写到磁盘上(Item.writer(file)),或者也可以自己使用 OuputStream 把文件写到磁盘上,这样可以做一些其他的操作,比如计算一个文件的上传进度反馈给用户。
相对 Item.write(),comment-fileupload 还提供了一种性能上更好的方式把文件写到磁盘上
try { // 对请求进行解释,得到一个文件条目的迭代器 FileItemIterator iter = upload.getItemIterator(request); // 进行迭代 while (iter.hasNext()){ FileItemStream item = iter.next(); String fieldName = item.getFieldName(); InputStream in = item.openStream(); // 进行判断 if(item.isFormField()){ // 得到参数的值 String fieldValue = Streams.asString(in); }else{ // 文件名 String fileName = item.getName(); // 创建一个输出流 OutputStream out = new BufferedOutputStream( new FileOutputStream(new File(filePath,fileName))); // 文件输出到磁盘 Streams.copy(in, out, true); } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }
参考: http://commons.apache.org/fileupload/using.html