commons-fileupload 檔案上傳之細節
阿新 • • 發佈:2018-12-13
目錄 1、把上傳的檔案放到WEB-INF目錄下 2、檔名稱(完整路徑、檔名稱) 3、中文亂碼問題 4、上傳檔案同名問題(檔案重新命名) 5、一個目錄不能存放過多的檔案(存放目錄打散) 6、上傳的單個檔案的大小限制和整個表單大小限制 7、快取大小與臨時目錄 ====================================================== 1、把上傳的檔案放到WEB-INF目錄下 如果沒有把使用者上傳的檔案存放到WEB-INF目錄下,那麼使用者就可以通過瀏覽器直接訪問上傳的檔案,這是非常危險的。 假如說使用者上傳了一個a.jsp檔案,然後使用者在通過瀏覽器去訪問這個a.jsp檔案,那麼就會執行a.jsp中的內容, 如果在a.jsp中有如下語句:Runtime.getRuntime().exec("shutdown –s –t 1");,那麼你就會… 通常我們會在WEB-INF目錄下建立一個uploads目錄來存放上傳的檔案,而在Servlet中找到這個目錄需要 使用ServletContext的getRealPath(String)方法,例如在我的upload1專案中有如下語句: ServletContext servletContext = this.getServletContext(); String savepath = servletContext.getRealPath("/WEB-INF/uploads"); 其中savepath為:"F:\tomcat6_1\webapps\upload1\WEB-INF\uploads" 2、檔名稱(完整路徑、檔名稱) 上傳檔名稱可能是完整路徑: 有些瀏覽器獲取的上傳檔名稱是完整路徑,大部分瀏覽器獲取的上傳檔名稱只是檔名稱而已。 瀏覽器差異的問題我們還是需要處理一下的。處理這一問題也很簡單,無論是否為完整路徑,我們都去擷取最後一個"\\"後面的內容就可以了。 String name = file1FileItem.getName(); int lastIndex = name.lastIndexOf("\\");//獲取最後一個"\"的位置 if(lastIndex != -1) {//注意,如果不是完整路徑,那麼就不會有"\"的存在。 name = name.substring(lastIndex + 1);//獲取檔名稱 } response.getWriter().print(name); 3、中文亂碼問題 當上傳的誰的名稱中包含中文時,需要設定編碼,commons-fileupload元件為我們提供了兩種設定編碼的方式: * request.setCharacterEncoding(String):這種方式是我們最為熟悉的方式了; * fileUpload.setHeaderEncdoing(String):這種方式是commons-fileupload元件中的,優先順序高與前一種。 上傳檔案的檔案內容包含中文: 通常我們不需關心上傳檔案的內容,因為我們會把上傳檔案儲存到硬碟上!也就是說,檔案原來是什麼樣子,到伺服器這邊還是什麼樣子! 但是如果你有這樣的需求,非要在控制檯顯示上傳的檔案內容,那麼你可以使用fileItem.getString("utf-8")來處理編碼。 文字檔案內容和普通表單項內容使用FileItem類的getString("utf-8")來處理編碼。 4、上傳檔案同名問題(檔案重新命名) 通常我們會把使用者上傳的檔案儲存到uploads目錄下,但如果使用者上傳了同名檔案呢?這會出現覆蓋的現象。 處理這一問題的手段是使用UUID生成唯一名稱,然後再使用"_"連線檔案上傳的原始名稱。 例如,使用者上傳的檔案是"我的一寸照片.jpg",在通過處理後,檔名稱為:"891b3881395f4175b969256a3f7b6e10_我的一寸照片.jpg", 這種手段不會使檔案丟失副檔名,並且因為UUID的唯一性,上傳的檔案同名,但在伺服器端是不會出現同名問題的。 5、一個目錄不能存放過多的檔案(存放目錄打散) 一個目錄下不應該存放過多的檔案,一般一個目錄存放1000個檔案就是上限了,如果在多,那麼開啟目錄時就會很"卡"。 你可以嘗試列印C:\WINDOWS\system32目錄,你會感覺到的。也就是說,我們需要把上傳的檔案放到不同的目錄中。 但是也不能為每個上傳的檔案一個目錄,這種方式會導致目錄過多。所以我們應該採用某種演算法來"打散"!打散的方法有很多, 例如,使用日期來打散,每天生成一個目錄。也可以使用檔名的首字母來生成目錄,相同首字母的檔案放到同一目錄下。 日期打散演算法:如果某一天上傳的檔案過多,那麼也會出現一個目錄檔案過多的情況; 首字母打散演算法:如果檔名是中文的,因為中文過多,所以會導致目錄過多的現象。 我們這裡使用hash演算法來打散: 1.獲取檔名稱的hashCode:int hCode = name.hashCode(); 2.將hCode轉換成16進位制字元; 3.使用這個16進位制的字元的前兩個字元生成目錄鏈。 int hCode = name.hashCode();//獲取檔名的hashCode String dir = Integer.toHexString(hCode); //與檔案儲存目錄連線成完整路徑 savepath = savepath + "/" + dir.charAt(0) + "/" + dir.charAt(1); //因為這個路徑可能不存在,所以建立成File物件,再建立目錄鏈,確保目錄在儲存檔案之前已經存在 new File(savepath).mkdirs(); 6、上傳的單個檔案的大小限制和整個表單大小限制 限制上傳檔案的大小很簡單,ServletFileUpload類的setFileSizeMax(long)就可以了。引數就是上傳檔案的上限位元組數, 例如servletFileUpload.setFileSizeMax(1024*10)表示上限為10KB。一旦上傳的檔案超出了上限, 那麼就會丟擲FileUploadBase.FileSizeLimitExceededException異常。我們可以在Servlet中獲取這個異常, 然後向頁面輸出"上傳的檔案超出限制"。 public void doPost(HttpServletRequest request, HttpServletResponse response) throws Exception { request.setCharacterEncoding("utf-8"); DiskFileItemFactory dfif = new DiskFileItemFactory(); ServletFileUpload fileUpload = new ServletFileUpload(dfif); fileUpload.setFileSizeMax(1024 * 10); // 設定上傳的單個檔案的上限為10KB fileUpload.setSizeMax(1024 * 200); //設定整個請求的上限為200KB try { List<FileItem> list = fileUpload.parseRequest(request); ...... fileItem.write(file); } catch (Exception e) { // 判斷丟擲的異常的型別是否為FileUploadBase.FileSizeLimitExceededException // 如果是,說明上傳檔案時超出了限制。 if(e instanceof FileUploadBase.FileSizeLimitExceededException) { request.setAttribute("msg", "上傳失敗!上傳的檔案超出了10KB!"); request.getRequestDispatcher("/index.jsp").forward(request, response); return; } if(e instanceof FileUploadBase.SizeLimitExceededException) { request.setAttribute("msg", "上傳失敗!整個表單上傳的檔案超出了200KB!"); request.getRequestDispatcher("/index.jsp").forward(request, response); return; } throw new ServletException(e); } } 7、快取大小與臨時目錄 如果上傳一個藍光電影,先把電影儲存到記憶體中,然後再通過記憶體copy到伺服器硬碟上,那麼你的記憶體能吃的消麼? 所以fileupload元件不可能把檔案都儲存在記憶體中,fileupload會判斷檔案大小是否超出10KB, 如果超出,是那麼就把檔案儲存到硬碟上;如果沒有超出,那麼就儲存在記憶體中。 10KB是fileupload預設的值,我們可以來設定它。 當檔案儲存到硬碟時,fileupload是把檔案儲存到系統臨時目錄,當然你也可以去設定臨時目錄。 public void doPost(HttpServletRequest request, HttpServletResponse response) throws Exception { DiskFileItemFactory dfif = new DiskFileItemFactory(1024*20, new File("F:\\temp")); //設定快取大小20KB 及目錄 ...... }