昨天作了一個Servlet實現文件上傳的功能,以前沒仔細研究過commons-fileupload-1.2.1.jar,就隨意網上搜了下例子,草率寫完了,測試成功,感受不錯沒出什麼問題,回來無心之間又看到一篇文章說,用commons-fileupload-1.2.1.jar實現上傳文件必定要加上commons-io-1.3.2.jar,我就開始納悶了,我明明沒有加這個io包測試成功,他竟然說必須加,感受確定是有問題的,通過今天一上午研究最後終於找出緣由爲何有人說加有人說不加啦,預知詳情,請不要走開,java
1,先把個人servlet簡單的寫出來,還有個jsp,沒什麼內容就幾個<input type="file" >,就不列出來了,不要忘了form里加上enctype="multipart/form-data",沒這個貌似不能夠的。apache
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("UTF-8"); FileBiz biz = new FileBiz(); String uploadPath = getServletContext().getRealPath("/");//獲取文件路徑 biz.upload(request,uploadPath); response.getWriter().println("上傳成功"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); }
2,列下我第一次沒有加commons-io-1.3.2.jar狀況下測試成功的代碼。windows
public class FileBiz { public void upload(HttpServletRequest request,String uploadPath) { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss"); File tmpDir = new File("d:\\temp"); //初始化上傳文件的臨時存放目錄,必須是絕對路徑 try { if (ServletFileUpload.isMultipartContent(request)) { DiskFileItemFactory factory = new DiskFileItemFactory(); //指定在內存中緩存數據大小,單位爲byte,這裏設爲1Mb factory.setSizeThreshold(1 * 1024 * 1024); //設置一旦文件大小超過getSizeThreshold()的值時數據存放在硬盤的目錄 factory.setRepository(tmpDir); ServletFileUpload sfu = new ServletFileUpload(factory); // 指定單個上傳文件的最大尺寸,單位:字節,這裏設爲5Mb sfu.setFileSizeMax(5 * 1024 * 1024); //指定一次上傳多個文件的總尺寸,單位:字節,這裏設爲10Mb sfu.setSizeMax(10 * 1024 * 1024); sfu.setHeaderEncoding("UTF-8"); //設置編碼,由於個人jsp頁面的編碼是utf-8的 FileItemIterator fii = sfu.getItemIterator(request);// 解析request請求 uploadPath = uploadPath + "upload\\"; // 選定上傳的目錄此處爲當前目錄 if (!new File(uploadPath).isDirectory()){ new File(uploadPath).mkdirs(); //選定上傳的目錄此處爲當前目錄,沒有則建立 } int index = 0; while (fii.hasNext()) { FileItemStream fis = fii.next();// 從集合中得到一個文件流 if (!fis.isFormField() && fis.getName().length() > 0) {// 過濾掉表單中非文件域 String fileName = fis.getName().substring( fis.getName().lastIndexOf("."));// 得到上傳文件的文件名 fileName = sdf.format(new Date())+"-"+index+fileName; BufferedInputStream in = new BufferedInputStream(fis.openStream()); BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream(new File(uploadPath + "\\" + fileName))); Streams.copy(in, out, true); // 開始把文件寫到你指定的上傳文件夾 index++; } } } } catch (Exception e) { e.printStackTrace(); } } }
注意這裏的寫入文件時調用是commons.fileupload.util.Streams工具類的靜態方法。緩存
以上就能夠實現上傳了,這個是支持多文件上傳的。tomcat
3,我想既然有人說須要加commons-io包的,要麼是環境跟個人不同,要麼是實現的方法跟個人不同,個人環境是jsp
windows +tomcat6.0+jdk1.5,環境不容易改變,只有改變方法啦。工具
改變後的load方法。性能
public void uploads(HttpServletRequest request,String uploadPath){ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss"); File tmpDir = new File("d:\\temp"); try { if (ServletFileUpload.isMultipartContent(request)) { DiskFileItemFactory factory = new DiskFileItemFactory(); factory.setSizeThreshold(1 * 1024 * 1024); factory.setRepository(tmpDir); ServletFileUpload sfu = new ServletFileUpload(factory); sfu.setFileSizeMax(5 * 1024 * 1024); sfu.setSizeMax(10 * 1024 * 1024); sfu.setHeaderEncoding("UTF-8"); List<FileItem> fileItems = sfu.parseRequest(request); uploadPath = uploadPath + "upload\\"; if (!new File(uploadPath).isDirectory()){ new File(uploadPath).mkdirs(); } int leng = fileItems.size(); for(int n=0;n<leng;n++) { FileItem item = fileItems.get(n); // 從集合中得到一個文件流 // 若是是普通表單字段 if(item.isFormField()) { String name = item.getFieldName(); // 得到該字段名稱 String value = item.getString("utf-8"); //得到該字段值 System.out.println(name+value); }else if(item.getName().length()>0) { // 若是爲文件域 String iname = item.getName().substring( item.getName().lastIndexOf(".")); String fname=sdf.format(new Date())+"-"+n+iname; try { item.write(new File(uploadPath, fname)); // 寫入文件 } catch (Exception e) { e.printStackTrace(); } } } } }catch (Exception e) { e.printStackTrace(); } }
一測試,不行啦,報錯了,立刻加上commons-io-1.3.2.jar,再測試,OK。測試
原來是實現方法不同,說不須要加包的都是基於第一種方法實現的,說須要加的都是第二種。this
必須知道爲何會這樣,下載commons-fileupload-1.2.1.jar源代碼看看,
找到第一種方法源代碼以下
public static long copy(InputStream pIn, OutputStream pOut, boolean pClose, byte[] pBuffer) throws IOException { OutputStream out = pOut; InputStream in = pIn; try { long total = 0; for (;;) { int res = in.read(pBuffer); if (res == -1) { break; } if (res > 0) { total += res; if (out != null) { out.write(pBuffer, 0, res); } } } if (out != null) { if (pClose) { out.close(); } else { out.flush(); } out = null; } in.close(); in = null; return total; } finally { if (in != null) { try { in.close(); } catch (Throwable t) { /* Ignore me */ } } if (pClose && out != null) { try { out.close(); } catch (Throwable t) { /* Ignore me */ } } } }
第二種源代碼以下,FileItem是個interface,要找DiskFileItem類,
import org.apache.commons.io.IOUtils; import org.apache.commons.io.output.DeferredFileOutputStream; public class DiskFileItem implements FileItem, FileItemHeadersSupport {
FileItem.write方法就是DiskFileItem.write方法,其中寫文件時用的就是IOUitls類寫的,
BufferedInputStream in = null; BufferedOutputStream out = null; try { in = new BufferedInputStream( new FileInputStream(outputFile)); out = new BufferedOutputStream( new FileOutputStream(file)); IOUtils.copy(in, out); } finally { if (in != null) { in.close(); } if (out != null) { out.close(); } } //方法有點長,把主要挖出來
最後還測試了下性能問題,簡單測試顯示第二種方法比快不少,畢竟commons-io-1.3.2.jar是專業處理io的嘛,哈哈
這應該就是加不加commons-io-1.3.2.jar的緣由了吧。。