原文網頁http://commons.apache.org/fileupload/using.html
使用 FileUpload
FileUpload取決於你的程式要求,可以用在許多不同的地方。在最簡單的情況下,你可以用一個method來解析servlet 的request,然後將清單中的項目使用在程式裡。另一方面,你可以制定每個檔案上傳時所使用的方式,例如:你可以決定檔案上傳至資料庫所用的串流(stream )類型。
在這裡,我們將說明FileUpload的基本運作模式,並說明了一些比較簡單和最常見的的使用範例。自定義的FileUpload 說明。
FileUpload 以Commons IO為基礎,所以一定要確保你有相關頁面中的版本,並且存在你的classpath中。
它是如何運作的:
一個文件上傳request 中含有items 的清單,其中內容是以RFC 1867 來編碼的, "Form-based File Upload in HTML"。FileUpload可以解析這類request,並提供items 的清單給你的程式。每一個item都實現(implements) FileItemInterface,不論其底層的實現。
本文章將教導讀者來使用傳統的commons FileUpload API。傳統的API是一個方便的方法,然而這裡也提供速度更快的串流 API 。
每個item 檔案都帶有屬性,而你的程式可能會需要它們。例如,每一個item 都有name 和type 來提供InputStream 處理。另外,你可能會對不同的item 做不同的處理,例如上傳的圖片和圖片說明文字可能要存在不同的地方。FileItem interface 提供了方法來處理上述的例子,並以最佳的方式處理資料。
FileUpload 用FileItemFactory來新建檔案,這使得檔案上傳更有靈活性。FileItemFactory 對每個item 做最後的控制。FileItemFactory 能夠以資料大小來決定資料要存進記憶體還是硬碟。然而,這種規則可以自由訂製,以滿足程式上的需求。
FileUpload 從版本1.1開始,支持文件在servlet和portlet的環境上傳。這兩個環境下的用法幾乎是相同的,因此本文章接下來的環境都以servlet來做說明。
如果你要建立一個portlet 應用程式,請注意下面兩點與servlet不同的地方:
- 當引用ServletFileUpload類的時候,請以PortletFileUpload類來替代。
- 當引用HttpServletRequest類的時候,請以ActionRequest類來替代。
在處理上傳的items之前,你當然必須先解析request。你很容易可以知道request 的內容是不是要上傳檔案,但FileUpload 可以讓它變得更加簡單,它提供了一個靜態方法:
|
得知這是一個檔案上傳request 之後,我們就可以繼續解析其內容items。
譯者補充:其實判斷句判斷的依據是 <form enctype="multipart/form-data" method="post" action="Sverlet"> 中的enctype內容 |
最簡單的例子
最簡單的用法如下:
- 上傳的items如果是相對較小的,則應該保留在記憶體中。
- 較大的items應寫入到硬碟上的暫存檔案。
- 不應該允許超大檔案的上傳請求。
- 記憶體預設的最大使用空間、檔案的大小上限、暫存檔案的目錄都是可以被存取的。
最簡單的處理request 的情況:
|
只需要以上這些動作就完成了。真的!
分析request可以得到一個List,裡面是實作了FileItem 介面的items處理這些items的方法將在下面討論。
即使你所需要的操作很接近上述的簡單例子,你還是需要多一點的控制,像是上傳的設定或是FileItemFactory 中的設定。以下是一些配置的範例:
|
當然,每個配置方法是彼此獨立,但如果你想做整體的配置,你可以使用建構子來實現,像這樣:
|
如果您需要更進一步控制,例如將資料存入資料庫,請參閱自訂上傳。
一旦request的解析完成後,你會得到一個List,裡面就是你要處理的items。在大多數情況下,你可能會需要對不同檔案的來源做不同的處理,像這樣做:
|
對於普通的表格,你通常只會對它的name 和它的String值做處理。
|
對於檔案上傳,在處理內容之前,你可能會想先知道一些關於檔案的訊息。下面是一些比較常見的的例子
|
上傳文件的時候,你通常不會經由記憶體來處理,除非檔案很小,或者你有沒有其他選擇。相反的,直接用串流的方式來處理檔案,把整個檔案直接寫到最後的位置是最理想的。FileUpload 可以很容易的實現這兩種方法。
|
請注意,預設上,FileUpload 的write() 方法會在資料已經完全傳到暫存檔中之後嘗試重命名該檔案。即使重新命名失敗,複製檔案的動作也會告終,重新命名失敗可能出於某種原因,例如檔案是存在於記憶體中。
如果你要存取位於記憶體中的檔案,你可以使用get()方法來取得一個bytes矩陣的資料。
|
資源清理
本節僅適用於DiskFileItem 的使用者。如果您上傳的檔案在被寫入到暫存檔之前就要做處理,那麼閱讀這節會有幫助。
如果暫存檔不再被使用時,就會被自動刪除,(更確切地說,在java.io.File中有garbage collecter,而在這裏是org.apache.commons.io.FileCleaner會有個執行序來做資源回收的動作。
資源回收執行序不再需要時,應該被停止。在servlet環境中,會有一個特殊的servlet上下文listener來做這樣的事情,稱為 FileCleanerCleanup 。要做到這一點,在web.xml 中加入以下標籤:
|
FileCleanerCleanup提供了一個實例org.apache.commons.io.FileCleaningTracker. 當建立org.apache.commons.fileupload.disk.DiskFileItemFactory 時,FileCleaningTracker實例必須被使用。請參考下面的做法:
|
把FileCleaningTracker 設為null 以停止追蹤暫存檔。這樣一來創建的檔案將不再被追蹤,也不再被自動刪除。
在使用FileUpload 時,同時在一個web container底下運作多個防毒程序可能會有意料之外的結果。本節介紹您可能會遇到的一些行為,並提供了一些處理它們方法。
使用FileUpload 來傳送檔案到磁碟中,當傳送結束,檔案被關閉之後,系統上的病毒掃描程序將會開始檢查該檔案。如果該檔案被查出有問題,就會被防毒軟體移動到隔離所或刪除。這樣一來,我們的檔案處理程序就會出現意外,因為檔案已經不存在。另一方面,上傳的項目仍然被保存在記憶體中,因此不會被掃毒軟體發現。這可能會讓病毒有機會留下來(雖然最後檔案還是會進到硬碟被掃毒軟體檢查)。
一個常用的解決方案是把所有上傳的檔案放在一個特定的目錄中,並設定防毒軟體忽略該目錄。這能夠確保檔案不會發生像上述一樣的事情。詳細的掃毒不在本文詳述範圍。
如果會遇到大檔案的上傳,那進度條會是一個很好的表現方法來告知使用者上傳的情況。即使是HTML頁面,也可以實現進度條,通過回傳 multipart/replace 之類的response。
使用進度條會用到一個listener:
|
你可以試試看把上面這個listener 用在你的進度條上,你會發現有個問題存在:listener 被呼叫的頻率非常高因為它可能會被所有網路封包給觸發!換句話說,你的進度條會造成電腦的負擔!這裡提供一個典型的解決方案,減少進度監聽活動。例如,您可以只監聽Mb為單位的變動:
|
接下來?
希望這篇文章對你有幫助對於如何上傳檔案。方法詳細介紹以及其他可用的方法,請參考JavaDoc。
這裡所描述的用法應滿足大部分的檔案上傳需要。如果你有更進階的需要,FileUpload也可以提供更多的功能來使用
留言列表