利用commons-fileupload 實現文件上傳終極版及commons-fileuplo...

昨天作了一個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的緣由了吧。。

相關文章
相關標籤/搜索