1.RFC1867協議
最初的
為
2.1客戶端
簡單來說,RFC1867規范要求http協議增加了file類型的input標簽,用于瀏覽需要上傳的文件。同時要求FORM表單的enctype屬性設置為“multipart/form-data”,method屬性設置為“post”即可,下面是我們文件上傳頁面的表單代碼:
<form
文本1:<input
文件2:<input
文件1:<input
文件2:<input
文件2:<input
<input
</form>
2.2
一個文件上傳請求的消息實體由一系列根據
DiskFileItemFactory
ServletFileUpload
List<FileItem>
if
//
String
String
}
//將臨時文件保存到指定目錄
String
String
item.write(new
}
FileItem接口
org.apache.commons.fileupload.disk.DiskFileItem實現了FileItem接口,用來封裝單個表單字段元素的數據。通過調用FileItem
下圖是一個文件上傳表單:
...............
...............
...............
上圖表單提交的http數據包的內容:
POST
Accept:
Referer:
Accept-Language:
Content-Type:
UA-CPU:
Accept-Encoding:
User-Agent:
Host:
Content-Length:
Connection:
Cache-Control:
Cookie:
-----------------------------7da1772c5504c6
Content-Disposition:
鄭州蜂鳥科技有限公司
-----------------------------7da1772c5504c6
Content-Disposition:
申林
-----------------------------7da1772c5504c6
Content-Disposition:
Content-Type:
大量二進制數據內容,無法復制
-----------------------------7da1772c5504c6
Content-Disposition:
Content-Type:
大量二進制數據內容,無法復制
-----------------------------7da1772c5504c6
Content-Disposition:
Content-Type:
大量二進制數據內容,無法復制
從第一行,也就是請求行,我們可以看出這是一個post請求。在請求頭部部分,我們可以看到這樣一個頭部信息:
Content-Type:
其中紅色部分說明該請求是一個multipart/form-data類型即多媒體類型的請求。藍色部分boundary的值定義了一個字段分隔界線。
在消息體部分可以看出每個表單字段元素數據之間采用字段分隔界線進行分割,兩個分隔界線間的內容稱為一個分區,每個分區中的內容包括兩部分,一部分是對表單字段元素進行描述的描述頭,另外一部分是表單字段元素的主體內容。
通過對比描述頭,我們可以很容易區分文本字段和文件字段。不管是文件字段還是文本字段,都有name屬性,即該字段作為一個表單域的名字。而文件字段還有filename,即上傳文件本身的名字。另外,還有conten-type屬性用于指明文件的類型。
每一個表單字段,不管它是文本還是文件,都被封裝成
FileItem類內部提供了維護臨時文件名中的數值不重復的機制,以保證了臨時文件名的唯一性。另外,如何保證臨時文件能被及時清除,釋放寶貴的系統資源,是非常重要的,我們將在后面講解。
FileItem類常用的方法:
1.
isFormField方法用于判斷FileItem類對象封裝的數據是一個普通文本表單字段,還是一個文件表單字段,如果是普通表單字段則返回true,否則返回false。
2.
getName方法用于獲得文件上傳字段中的文件名,即表單字段元素描述頭中的filename屬性值,如“C:/Documents
如果FileItem類對象對應的是普通表單字段,getName方法將返回null。即使用戶沒有通過網頁表單中的文件字段傳遞任何文件,但只要設置了文件表單字段的name屬性,瀏覽器也會將文件字段的信息傳遞給服務器,只是文件名和文件內容部分都為空,但這個表單字段仍然對應一個FileItem對象,此時,getName方法返回結果為空字符串"",讀者在調用Apache文件上傳組件時要注意考慮這個情況。
注意:上面的數據包是通過IE提交,所以是完整的路徑和名稱。如
3.
getFieldName方法用于返回表單字段元素描述頭的name屬性值,也是表單標簽name屬性的值。例如“name=file1”中的“file1”。
4.
write方法用于將FileItem對象中保存的主體內容保存到某個指定的文件中。如果FileItem對象中的主體內容是保存在某個臨時文件中,該方法順利完成后,臨時文件有可能會被清除。該方法也可將普通表單字段內容寫入到一個文件中,但它主要用途是將上傳的文件內容保存在本地文件系統中。
5.
getString方法用于將FileItem對象中保存的數據流內容以一個字符串返回,它有兩個重載的定義形式:
public
public
throws
前者使用缺省的字符集編碼將主體內容轉換成字符串,后者使用參數指定的字符集編碼將主體內容轉換成字符串。如果在讀取普通表單字段元素的內容時出現了中文亂碼現象,請調用第二個getString方法,并為之傳遞正確的字符集編碼名稱。
6.
getContentType
7.
isInMemory方法用來判斷FileItem對象封裝的數據內容是存儲在內存中,還是存儲在臨時文件中,如果存儲在內存中則返回true,否則返回false。
8.
delete方法用來清空FileItem類對象中存放的主體內容,如果主體內容被保存在臨時文件中,delete方法將刪除該臨時文件。
盡管當FileItem對象被垃圾收集器收集時會自動清除臨時文件,但及時調用delete方法可以更早的清除臨時文件,釋放系統存儲資源。另外,當系統出現異常時,仍有可能造成有的臨時文件被永久保存在了硬盤中。
9.
10.
返回該上傳文件的大?。ㄒ宰止潪閱挝唬?/p>
DiskFileItemFactory類
將請求消息實體中的每一個項目封裝成單獨的
屬性
1)
將文件保存在內存還是磁盤臨時文件夾的默認臨界值,值為10240,即10kb。
2)
用于配置在創建文件項目時,當文件項目大于臨界值時使用的臨時文件夾,默認采用系統默認的臨時文件路徑,可以通過系統屬性
System.getProperty("java.io.tmpdir");
3)
用于保存將文件保存在內存還是磁盤臨時文件夾的臨界值
構造方法
1)
采用默認臨界值和系統臨時文件夾構造文件項工廠對象。
2)
采用參數指定臨界值和系統臨時文件夾構造文件項工廠對象。
FileItem
根據DiskFileItemFactory相關配置將每一個請求消息實體項目創建
void
Apache文件上傳組件在解析上傳數據中的每個字段內容時,需要臨時保存解析出的數據,以便在后面進行數據的進一步處理(保存在磁盤特定位置或插入數據庫)。因為Java虛擬機默認可以使用的內存空間是有限的,超出限制時將會拋出“java.lang.OutOfMemoryError”錯誤。如果上傳的文件很大,例如800M的文件,在內存中將無法臨時保存該文件內容,Apache文件上傳組件轉而采用臨時文件來保存這些數據;但如果上傳的文件很小,例如600個字節的文件,顯然將其直接保存在內存中性能會更加好些。
setSizeThreshold方法用于設置是否將上傳文件已臨時文件的形式保存在磁盤的臨界值(以字節為單位的int值),如果從沒有調用該方法設置此臨界值,將會采用系統默認值10KB。對應的getSizeThreshold()
void
setRepositoryPath方法用于設置當上傳文件尺寸大于setSizeThreshold方法設置的臨界值時,將文件以臨時文件形式保存在磁盤上的存放目錄。有一個對應的獲得臨時文件夾的
注意:當從沒有調用此方法設置臨時文件存儲目錄時,默認采用系統默認的臨時文件路徑,可以通過系統屬性
System.getProperty("java.io.tmpdir");
Tomcat系統默認臨時目錄為“<tomcat安裝目錄>/temp/”。
ServletFileUpload
org.apache.commons.fileupload.servlet.ServletFileUpload類是Apache文件上傳組件處理文件上傳的核心高級類(所謂高級就是不需要管底層實現,暴露給用戶的簡單易用的接口)。
使用其
如果你希望進一步提高新能,你可以采用
在使用ServletFileUpload對象解析請求時需要根據DiskFileItemFactory對象的屬性
所以,我們需要在進行解析工作前構造好DiskFileItemFactory對象,通過ServletFileUpload對象的構造方法或setFileItemFactory()方法設置
ServletFileUpload繼承結構:
java.lang.Object
|—org.apache.commons.fileupload.FileUploadBase
|—org.apache.commons.fileupload.servlet.ServletFileUpload
構造方法:
1)
構造一個未初始化的實例,需要在解析請求之前先調用setFileItemFactory()方法設置
2)
構造一個實例,并根據參數指定的FileItemFactory
ServletFileUpload類常用方法:
1.
setSizeMax方法繼承自FileUploadBase類,用于設置請求消息實體內容(即所有上傳數據)的最大尺寸限制,以防止客戶端惡意上傳超大文件來浪費服務器端的存儲空間。其參數是以字節為單位的long型數字。
在請求解析的過程中,如果請求消息體內容的大小超過了setSizeMax方法的設置值,將會拋出FileUploadBase內部定義的SizeLimitExceededExcepti
org.apache.commons.fileupload.FileUploadBase$SizeLimitExceededExcepti
該方法有一個對應的讀方法:public
2.
setFileSizeMax方法繼承自FileUploadBase類,用于設置單個上傳文件的最大尺寸限制,以防止客戶端惡意上傳超大文件來浪費服務器端的存儲空間。其參數是以字節為單位的long型數字。該方法有一個對應的讀方法:public
在請求解析的過程中,如果單個上傳文件的大小超過了setFileSizeMax方法的設置值,將會拋出FileUploadBase內部定義的FileSizeLimitExceededExc
org.apache.commons.fileupload.FileUploadBase$FileSizeLimitExceededExc
3.
parseRequest
該方法拋出FileUploadException異常來處理諸如文件尺寸過大、請求消息中的實體內容的類型不是“multipart/form-data”、IO異常、請求消息體長度信息丟失等各種異常。每一種異常都是FileUploadException的一個子類型。
4.
getItemIterator方法和parseRequest
5.
isMultipartContent方法方法用于判斷請求消息中的內容是否是“multipart/form-data”類型,是則返回true,否則返回false。isMultipartContent方法是一個靜態方法,不用創建ServletFileUpload類的實例對象即可被調用。
6.
方法繼承自FileUpload類,用于設置和讀取fileItemFactory屬性。
7.
設置文件上傳進度監聽器。關于監聽器的具體內容,將在后面學習。該方法有一個對應的讀取方法:ProgressListener
8.public
在文件上傳請求的消息體中,除了普通表單域的值是文本內容以外,文件上傳字段中的文件路徑名也是文本,在內存中保存的是它們的某種字符集編碼的字節數組,Apache文件上傳組件在讀取這些內容時,必須知道它們所采用的字符集編碼,才能將它們轉換成正確的字符文本返回。
setHeaderEncoding方法繼承自FileUploadBase類,用于設置上面提到的字符編碼。如果沒有設置,則對應的讀方法getHeaderEncoding()方法返回null,將采用HttpServletRequest設置的字符編碼,如果HttpServletRequest的字符編碼也為null,則采用系統默認字符編碼??梢酝ㄟ^一下語句獲得系統默認字符編碼:
System.getProperty("file.encoding"));
新聞熱點
疑難解答