1. 程式人生 > >commons-fileupload使用者指南(文件翻譯)

commons-fileupload使用者指南(文件翻譯)

使用fileupload

根據你的應用需求,fileupload可以有許多不同的使用方式。在最簡單的情況下,你可以呼叫一個簡單的方法來解析servlet請求,然後在他們提交到你的應用時處理表單列表。在其它規模的終端上,你也可能決定將fileupload進行自定義,以完全控制個別表單項儲存的方法。比如,你或許會將內容流化來儲存到資料中。
在這裡。我們將要描述fileupload的基本使用方法,然後解釋一些更簡單的,以及最常用的使用模式。fileupload的個性化在這裡得到了描述。

它怎麼工作

一個檔案上傳請求由有序表單項的列表組成,這些表單是根據RFC1867來編碼的,是在html中基於表單的檔案上傳。fileupload能解析這樣一個請求然後向你的應用提供一個單獨的上傳表單項的列表。每一個這樣的表單項實現了FileItem介面,而不需要考慮它潛在的實現方式。每個檔案的表單項擁有一系列可能對你的應用有用的屬性,比如,每個專案都有一個名字和檔案型別,你就可以提供一個InputStream來取它的資料。從另一方面說,你可能需要對這些選項進行不同的處理,這個可以根據對這個選項是不是一個規則的表單項來判斷,即可以根據這個資料是否來源於普通的文字框或者一個簡單的html表單域,還是一個能被上傳的檔案。FileItem介面提供了多種方法來判斷它是否是一個可上傳的檔案,然後你就可以用最合適的方式來處理這些資料了。FileUpload使用FileItemFactory來建立新的檔案專案。這正是給FileUpload帶來靈活性的原因。這個工廠最終控制每個專案的建立。預設的工廠在記憶體或者磁碟上儲存了專案的資料,這個可以根據專案的大小來定(例如,位元組資料)。當然,這個動作可以通過自定義來滿足你應用的需要。

解析請求

在你對要上傳的選項處理之前,很顯然的你得先解析這些請求本身。很直接的就是要確保這個請求是不是一個要上傳的檔案,然而FileUpload使這一點簡單化了,你只需提供一個靜態的方法來做到這一點。

--------------------------------------------------------------------------------
//檢查是否是一個檔案上傳請求
boolean isMultipart = FileUpload.isMultipartContent(request);

--------------------------------------------------------------------------------
現在我們就可以準備解析這個請求到一個備選的選項了。解析的結果是一個檔案選項的List,每個這樣的選項都實現了FileItem介面,處理這些選項將在下面得到討論。

最簡單的情況

最簡單的使用場景可以參照下面:

被上傳得選項必須以適度的大小駐留在記憶體中;
比較大的檔案上傳選項必須寫入到磁碟的臨時檔案中去;
大檔案上傳請求必須不被允許;
預設的駐留記憶體的選項的最大大小,最大允許的上傳檔案請求,和臨時檔案的儲存地方是可以接受的;
在這種情景下處理這樣一個請求並不是很簡單的:

--------------------------------------------------------------------------------
//建立一個新的檔案上傳控制代碼
DiskFileUpload upload = new DiskFileUpload();
//解析請求
List /* FileItem */ items = upload.parseRequest(request);

--------------------------------------------------------------------------------
這就是所有我們需要做的,真的!
解析的結果是一個檔案專案的List,每一個都實現了FileItem介面。處理這些專案將在下面討論。

練習更多的控制

如果你的使用情景非常接近最簡單的使用方式,在上文中可以看到,但是你需要更多的控制臨界的大小和臨時檔案的駐留地址,你可以使用DiskFileUpload類的方法來自定義這些動作,就像這樣:

--------------------------------------------------------------------------------
//建立一個新的檔案上傳控制代碼
DiskFileUpload upload = new DiskFileUpload();
//設定上傳引數
upload.setSizeThrehold(最大記憶體大小);
upload.setSizeMax(最大請求大小);
upload.setRepositoryPath(臨時目錄);
//解析請求
List /* FileItem */ items = upload.parseRequest(request);

--------------------------------------------------------------------------------
當然,每個配置方法都是獨立於其它的,但是如果你想一次就配置它們,你可以使用可選的parseRequest()方法,像這樣:

--------------------------------------------------------------------------------
// 建立一個新的檔案上傳控制代碼
DiskFileUpload upload = new DiskFileUpload();
// 解析請求
List /* FileItem */ items = upload.parseRequest(request,
        記憶體大小, 允許上傳的最大檔案, 臨時目錄);

--------------------------------------------------------------------------------
如果你想更多地控制請求的解析,比如把上傳選項儲存到其它地方,例如,存到資料庫中-你可以參照自定義FileUpload。

處理上傳選項

一旦解析過程完畢,你就可以獲得一個檔案選項的List,以便進一步處理。在大多數情況下,你將會根據規則的表單域來不同地處理檔案的上傳。所以你可能以這樣的方式來處理:

--------------------------------------------------------------------------------
// 處理上傳的選項
Iterator iter = items.iterator();
while (iter.hasNext()) {
    FileItem item = (FileItem) iter.next();

    if (item.isFormField()) {
        processFormField(item);
    } else {
        processUploadedFile(item);
    }
}

--------------------------------------------------------------------------------
對於一個規則的表單域來說,你對它感興趣的可能就只有它的名字以及它的字串值。你也會想到,處理它們是簡單的:

--------------------------------------------------------------------------------
//處理一個規則表單域
if (item.isFormField()) {
    String name = item.getFieldName();
    String value = item.getString();
    ...
}

--------------------------------------------------------------------------------
而對於一個檔案的上傳,在你處理它的內容之前,可以有好多令你想知道的不同的東西,這裡有一個採用了一些你可能感興趣的方法的例子

--------------------------------------------------------------------------------
// 處理一個檔案上傳
if (!item.isFormField()) {
    String fieldName = item.getFieldName();
    String fileName = item.getName();
    String contentType = item.getContentType();
    boolean isInMemory = item.isInMemory();
    long sizeInBytes = item.getSize();
    ...
}

--------------------------------------------------------------------------------
對於這些上傳的檔案,你一般不想通過記憶體來存取它們,除非它們很小,或者你沒有其它好的方法,更進一步,你想將內容當作檔案流來處理,或者將整個檔案寫到最終的地址。FileUpload提供了簡單的方法來完成這些 操作。

--------------------------------------------------------------------------------
// 處理一個檔案上傳的情況
if (writeToFile) {
    File uploadedFile = new File(...);
    item.write(uploadedFile);
} else {
    InputStream uploadedStream = item.getInputStream();
    ...
    uploadedStream.close();
}

--------------------------------------------------------------------------------
注意到,在預設的FileUpload的實現中,write()方法將嘗試把檔案改名以將它儲存到特定的地點,如果資料已經在臨時檔案中了,如果重新命名失敗,實際的複製檔案就完成了(?),在其它原因看來,或者資料已經在記憶體中了。如果你的確需要在記憶體中取上傳的資料,你只需簡單的呼叫get()方法來把它當作一個字元陣列來獲得。

--------------------------------------------------------------------------------

// 在記憶體中處理一個上傳的檔案
byte[] data = item.get();
...

--------------------------------------------------------------------------------

和防毒軟體的相互作用

當web容器在執行時,而防毒軟體又同時執行在同樣的系統上,這種情況下在應用中使用FileUpload容易導致一些很難預料的事情.這部分將描述一些你可能要遇到的情況,我們會提供一些方法來處理它們。預設的FileUpload實現將會使超過它在記憶體中大小的上傳的選項寫入到磁碟。而當這樣的檔案關閉後,任何系統中的防毒軟體都會被喚醒,然後去檢查它,然後會潛在地隔離這個檔案--就是說,將它移動到一個不產生問題的特定地方。這樣一來,對開發者來說當然是一個意外,因為剛剛上傳的檔案將不能被處理了。從另一方面來說,小於設定的記憶體大小的那些上傳的檔案將被保持在記憶體中,這樣一來,將不會被防毒軟體所檢測到,這樣就有可能使病毒以某種方式駐留在了系統中了(雖然如果一旦它被寫入到磁碟,防毒軟體就會定位並檢測到它)。一個通用的解決方法是在系統中專門設定一個目錄來存放這些上傳的檔案,然後配置防毒軟體忽略這個目錄。這樣將確保上傳的檔案在系統中不被隔離,但是這樣就把掃描病毒的責任交給了應用程式的開發者了。掃描這些上傳的檔案的任務可以在外部的處理中實現。這樣可以將乾淨的檔案移動到一個“改進”過的地方,或者也可以把防毒整合到應用中去。至於怎麼將外部處理或整合病毒掃描到一個
應用,這個已經超出了本文件的討論範圍。

下一步是什麼

希望這個頁面能提供給你一個好的意見,讓你在你自己的應用中能使用FileUpload。更多關於這裡介紹的方法,以及其它可用的方法,你可以參照api文件。這裡介紹的用法已經可以滿足大多數的檔案上傳的需要了,當然,如果你還有更多的複雜的需求,使用它的靈活的自定義配置的能力,FileUpload一定可以能夠幫助你。