日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java 文件上传组件 Apache Commons FileUpload 应用指南(二)——FileUpload如何工作?

發布時間:2023/12/2 java 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 文件上传组件 Apache Commons FileUpload 应用指南(二)——FileUpload如何工作? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?在最初的?http?協議中,沒有上傳文件方面的功能。RFC1867("Form-based?File?Upload?in?HTML".)
?http?協議添加了這個功能。客戶端的瀏覽器,如?Microsoft?IE,?Mozila,?Opera?等,按照此規范將用
戶指定的文件發送到服務器。服務器端的網頁程序,如
?php,?asp,?jsp?等,可以按照此規范,解析出用戶
發送來的文件。

2.1客戶端

簡單來說,RFC1867規范要求http協議增加了file類型的input標簽,用于瀏覽需要上傳的文件。同時
要求
FORM表單的enctype屬性設置為“multipart/form-data”,method屬性設置為“post”即可,下面是我們文
件上傳頁面的表單代碼:

<form?action="<%=request.getContextPath()%>/servlet/SimpleUpload"?enctype="multipart/form-data"?
method
="post">

文本1<input?type="text"?name="text1"?value="文本1"><br>

文件2<input?type="text"?name="text2"?value="文本2"><br>

文件1<input?type="file"?name="file1"><br>

文件2<input?type="file"?name="file2"><br>

文件2<input?type="file"?name="file3"><br>

<input?type="submit"?value="開始上傳">

</form>

2.2?服務器端

一個文件上傳請求的消息實體由一系列根據?RFC1867"Form-based?File?Upload?in?HTML".)編碼的項目
(文本參數和文件參數)組成。自己編程來解析獲取這些數據是非常麻煩的,還需要了解
RFC1867規范對請
求數據編碼的相關知識。
FileUpload?可以幫助我們解析這樣的請求,將每一個項目封裝成一個實現了FileItem
接口的對象,并以列表的形式返回。所以,我們只需要了解FileUploadAPI如何使用即可,不用管它們的底
層實現。讓我們來看一個簡單文件上傳處理代碼:

DiskFileItemFactory?factory?=?new?DiskFileItemFactory();

ServletFileUpload?uploader?=?new?ServletFileUpload(factory);

List<FileItem>?list?=?uploader.parseRequest(request);

if?(item.isFormField()){

//?處理普通表單域

String?field?=?item.getFieldName();//表單域名

String?value?=?item.getString("GBK");

}?else?{

//將臨時文件保存到指定目錄

String?fileName?=?item.getName();//文件名稱

String?filepath?=?"您希望保存的目錄/"?+?fileName;

item.write(new?File(filepath));//執行保存

}

????怎么樣?簡單吧!下面我們來繼續了解一些必須了解的API

FileItem接口

org.apache.commons.fileupload.disk.DiskFileItem實現了FileItem接口,用來封裝單個表單字段元素的
數據。通過調用
FileItem?定義的方法可以獲得相關表單字段元素的數據。我們不需要關心DiskFileItem的具
體實現,在程序中可以采用
FileItem接口類型來對DiskFileItem對象進行引用和訪問。FileItem類還實現了
Serializable接口,以支持序列化操作。

下圖是一個文件上傳表單:



上圖表單提交的http數據包的內容:

POST?/demo/servlet/SimpleUpload?HTTP/1.1

Accept:?image/gif,?image/x-xbitmap,?image/jpeg,?image/pjpeg,?application/x-shockwave-flash,?application/msword,?
application/vnd.ms-excel,?application/vnd.ms-powerpoint,?*/*

Referer:?http://127.0.0.1:8080/demo/simpleUpload.jsp

Accept-Language:?zh-cn

Content-Type:?multipart/form-data;?boundary=---------------------------7da1772c5504c6

UA-CPU:?x86

Accept-Encoding:?gzip,?deflate

User-Agent:?Mozilla/4.0?(compatible;?MSIE?7.0;?Windows?NT?5.1;?.NET?CLR?2.0.50727)

Host:?127.0.0.1:8080

Content-Length:?184423

Connection:?Keep-Alive

Cache-Control:?no-cache

Cookie:?JSESSIONID=BD8E58E5BAD9B559C0262077FB5E0B4E

-----------------------------7da1772c5504c6

Content-Disposition:?form-data;?name="text1"

鄭州蜂鳥科技有限公司

-----------------------------7da1772c5504c6

Content-Disposition:?form-data;?name="text2"

申林

-----------------------------7da1772c5504c6

Content-Disposition:?form-data;?name="file1";?filename="C:\Documents?and?Settings\All?Users\
Documents\My?Pictures\示例圖片\Blue?hills.jpg"

Content-Type:?image/pjpeg

大量二進制數據內容,無法復制?…….

-----------------------------7da1772c5504c6

Content-Disposition:?form-data;?name="file2";?filename="C:\Documents?and?Settings\All?Users\
Documents\My?Pictures\示例圖片\
Sunset.jpg"

Content-Type:?image/pjpeg

大量二進制數據內容,無法復制?…….

-----------------------------7da1772c5504c6

Content-Disposition:?form-data;?name="file3";?filename="C:\Documents?and?Settings\All?Users\
Documents\My?Pictures\示例圖片\
Water?lilies.jpg"

Content-Type:?image/pjpeg

大量二進制數據內容,無法復制?…….

從第一行,也就是請求行,我們可以看出這是一個post請求。在請求頭部部分,我們可以看到這樣
一個頭部信息:

Content-Type:?multipart/form-data;?boundary=---------------------------7da1772c5504c6

其中紅色部分說明該請求是一個multipart/form-data類型即多媒體類型的請求。藍色部分boundary的值
定義了一個字段分隔界線。在消息體部分可以看出每個表單字段元素數據之間采用字段分隔界線進行分
割,兩個分隔界線間的內容稱為一個分區,每個分區中的內容包括兩部分,一部分是對表單字段元素進
行描述的描述頭,另外一部分是表單字段元素的主體內容。?

通過對比描述頭,我們可以很容易區分文本字段和文件字段。不管是文件字段還是文本字段,都有
name屬性,即該字段作為一個表單域的名字。而文件字段還有filename,即上傳文件本身的名字。另外,
還有
conten-type屬性用于指明文件的類型。

每一個表單字段,不管它是文本還是文件,都被封裝成?FileItem?對象,我們稱之為文件項,當文件
項數據內容尺寸小于
DiskFileItemFactory?的sizeThreshold?屬性設置的臨界值時,直接保存在內存中;否則,
將數據流以臨時文件的形式,保存在?
DiskFileItemFactory?的?repository?屬性指定的臨時目錄中。臨時文件
名形如“
upload_00000005(八位或八位以上的數字).tmp”。
FileItem類內部提供了維護臨時文件名中的
數值不重復的機制,以保證了臨時文件名的唯一性。另外,如何保證臨時文件能被及時清除,釋放寶貴
的系統資源,是非常重要的,我們將在后面講解。?

FileItem類常用的方法:

1.??boolean?isFormField()方法

isFormField方法用于判斷FileItem類對象封裝的數據是一個普通文本表單字段,還是一個文件表單字
段,如果是普通表單字段則返回true,否則返回false

2.??String?getName()方法?

getName方法用于獲得文件上傳字段中的文件名,即表單字段元素描述頭中的filename屬性值,如“C:\Documents?and?Settings\All?Users\Documents\My?Pictures\示例圖片\Sunset.jpg”。如果FileItem類對象對
應的是普通表單字段,
getName方法將返回null即使用戶沒有通過網頁表單中的文件字段傳遞任何
文件,但只要設置了文件表單字段的name屬性,瀏覽器也會將文件字段的信息傳遞給服務器,
只是文件名和文件內容部分都為空,但這個表單字段仍然對應一個
FileItem對象,此時,
getName
方法返回結果為空字符串
"",讀者在調用Apache文件上傳組件時要注意考慮這個情況。

注意:上面的數據包是通過IE提交,所以是完整的路徑和名稱。如?
C:\Documents?and?Settings\All?Users\Documents\My?Pictures\示例圖片\
Sunset.jpg。如果是其它瀏覽
器,如火狐和Chromium,則僅僅是名字,沒有路徑,如
Sunset.jpg

3.??String?getFieldName()方法

getFieldName方法用于返回表單字段元素描述頭的name屬性值,也是表單標簽name屬性的值。例
如“
name=file1”中的“file1”。

4.??void?write(File?file)方法

write方法用于將FileItem對象中保存的主體內容保存到某個指定的文件中。如果FileItem對象中的主
體內容是保存在某個臨時文件中,該方法順利完成后,臨時文件有可能會被清除。該方法也可將普通
表單字段內容寫入到一個文件中,但它主要用途是將上傳的文件內容保存在本地文件系統中。

5.??String?getString()方法

getString方法用于將FileItem對象中保存的數據流內容以一個字符串返回,它有兩個重載的定義形式:

public?java.lang.String?getString()

public?java.lang.String?getString(java.lang.String?encoding)

throws?java.io.UnsupportedEncodingException

前者使用缺省的字符集編碼將主體內容轉換成字符串,后者使用參數指定的字符集編碼將主體內容
轉換成字符串。
如果在讀取普通表單字段元素的內容時出現了中文亂碼現象,請調用第二個
getString方法,并為之傳遞正確的字符集編碼名稱。

6.??String?getContentType()方法

getContentType?方法用于獲得上傳文件的類型,即表單字段元素描述頭屬性“Content-Type”的值,
如“
image/jpeg”。如果FileItem類對象對應的是普通表單字段,該方法將返回null

7.??boolean?isInMemory()方法

isInMemory方法用來判斷FileItem對象封裝的數據內容是存儲在內存中,還是存儲在臨時文件中,
如果存儲在內存中則返回true,否則返回false

8.??void?delete()方法

delete方法用來清空FileItem類對象中存放的主體內容,如果主體內容被保存在臨時文件中,
delete方法將刪除該臨時文件。

盡管當FileItem對象被垃圾收集器收集時會自動清除臨時文件,但及時調用delete方法可以更早的
清除臨時文件,釋放系統存儲資源。另外,當系統出現異常時,仍有可能造成有的臨時文件被永久
保存在了硬盤中。

9.??InputStream?getInputStream()方法

????以流的形式返回上傳文件的數據內容。

10.?long?getSize()方法

返回該上傳文件的大小(以字節為單位)。

DiskFileItemFactory

將請求消息實體中的每一個項目封裝成單獨的DiskFileItem?(FileItem接口的實現)?對象的任務
由?
org.apache.commons.fileupload.FileItemFactory?接口的默認實現?
org.apache.commons.fileupload.disk.DiskFileItemFactory?來完成。當上傳的文件項目比較小時,直接保
存在內存中
(速度比較快)比較大時,以臨時文件的形式,保存在磁盤臨時文件夾(雖然速度
慢些,但是內存資源是有限的)。

屬性

1)?public?static?final?int?DEFAULT_SIZE_THRESHOLD?:將文件保存在內存還是
磁盤臨時文件夾的默認臨界值,值為10240,即10kb

2)?private?File?repository:用于配置在創建文件項目時,當文件項目大于臨界值時使
用的臨時文件夾,默認采用系統
默認的臨時文件路徑,可以通過系統屬性?java.io.tmpdir?
獲取。如下代碼:

System.getProperty("java.io.tmpdir");

3)?private?int?sizeThreshold用于保存將文件保存在內存還是磁盤臨時文件夾的臨界值

構造方法

1)?public?DiskFileItemFactory():采用默認臨界值和系統臨時文件夾構造文件項工廠對象。

2)?public?DiskFileItemFactory(int?sizeThreshold,File?repository):采用參數指定臨界值和系統臨時
文件夾構造文件項工廠對象。

FileItem?createItem()?方法

根據DiskFileItemFactory相關配置將每一個請求消息實體項目創建?成DiskFileItem?實例,并返回。
該方法從來不需要我們親自調用,FileUpload組件在解析請求時內部使用。

void?setSizeThreshold(int?sizeThreshold)

Apache文件上傳組件在解析上傳數據中的每個字段內容時,需要臨時保存解析出的數據,以便
在后面進行數據的進一步處理(保存在磁盤特定位置或插入數據庫)。因為
Java虛擬機默認可以使
用的內存空間是有限的,超出限制時將會拋出“
java.lang.OutOfMemoryError”錯誤。如果上傳的文件
很大,例如800M的文件,在內存中將無法臨時保存該文件內容,Apache文件上傳組件轉而采用臨時
文件來保存這些數據;但如果上傳的文件很小,例如
600個字節的文件,顯然將其直接保存在內存中
性能會更加好些。

setSizeThreshold方法用于設置是否將上傳文件已臨時文件的形式保存在磁盤的臨界值(以字節
為單位的
int值),如果從沒有調用該方法設置此臨界值,將會采用系統默認值10KB。對應的
getSizeThreshold()?方法用來獲取此臨界值。

void?setRepository(File?repository)

setRepositoryPath方法用于設置當上傳文件尺寸大于setSizeThreshold方法設置的臨界值時,將文件以
臨時文件形式保存在磁盤上的存放目錄。有一個對應的獲得臨時文件夾的?File?getRespository()?方法。

注意:當從沒有調用此方法設置臨時文件存儲目錄時,默認采用系統默認的臨時文件路徑,可以
通過系統屬性?
java.io.tmpdir?獲取。如下代碼:

System.getProperty("java.io.tmpdir");

Tomcat系統默認臨時目錄為“<tomcat安裝目錄>/temp/”。

ServletFileUpload?類

org.apache.commons.fileupload.servlet.ServletFileUpload類是Apache文件上傳組件處理文件上傳的
核心高級類(所謂高級就是不需要管底層實現,暴露給用戶的簡單易用的接口)。

使用其?parseRequest(HttpServletRequest)?方法可以將通過表單中每一個HTML標簽提交的數據封裝
成一個
FileItem對象,然后以List列表的形式返回。使用該方法處理上傳文件簡單易用。

如果你希望進一步提高新能,你可以采用?getItemIterator?方法,直接獲得每一個文件項的數據輸
入流,對數據做直接處理。

在使用ServletFileUpload對象解析請求時需要根據DiskFileItemFactory對象的屬性?sizeThreshold(臨
界值)和
repository(臨時目錄)?來決定將解析得到的數據保存在內存還是臨時文件中,如果是臨時
文件,保存在哪個臨時目錄中?。所以,我們需要在進行解析工作前構造好
DiskFileItemFactory對象,
通過ServletFileUpload對象的構造方法或
setFileItemFactory()方法設置?ServletFileUpload對象的
fileItemFactory屬性。

ServletFileUpload繼承結構:

java.lang.Object

|org.apache.commons.fileupload.FileUploadBase

?????|org.apache.commons.fileupload.FileUpload

|org.apache.commons.fileupload.servlet.ServletFileUpload

構造方法:

1)?public?ServletFileUpload():構造一個未初始化的實例,需要在解析請求之前先調用
setFileItemFactory()方法設置?fileItemFactory屬性。

2)?public?ServletFileUpload(FileItemFactory?fileItemFactory):構造一個實例,并根據參數
指定的
FileItemFactory?對象,設置?fileItemFactory屬性。

ServletFileUpload類常用方法:

1.?public?void?setSizeMax(long?sizeMax)方法

setSizeMax方法繼承自FileUploadBase類,用于設置請求消息實體內容(即所有上傳數據)的最大
尺寸限制,
以防止客戶端惡意上傳超大文件來浪費服務器端的存儲空間。其參數以字節為單位的
long型數字

在請求解析的過程中,如果請求消息體內容的大小超過了setSizeMax方法的設置值,將會拋出
FileUploadBase內部定義的SizeLimitExceededException異常(FileUploadException的子類)。如:

org.apache.commons.fileupload.FileUploadBase$SizeLimitExceededException:?
the?request?was?rejected?because?its?size?(1649104)?exceeds?the?configured?
maximum?(153600)

該方法有一個對應的讀方法:public?long?getSizeMax()方法。

2.?public?void?setFileSizeMax(long?fileSizeMax)方法

setFileSizeMax方法繼承自FileUploadBase類,用于設置單個上傳文件的最大尺寸限制,以防止客戶
端惡意上傳超大文件來浪費服務器端的存儲空間。其
參數以字節為單位的long型數字。該方法有一個
對應的讀方法:public?long?geFileSizeMax()方法。

在請求解析的過程中,如果單個上傳文件的大小超過了setFileSizeMax方法的設置值,將會拋出
FileUploadBase內部定義的FileSizeLimitExceededException異常(FileUploadException的子類)。如:

org.apache.commons.fileupload.FileUploadBase$FileSizeLimitExceededException:?The?field?file1?exceeds?its
?maximum?permitted?size?of?51200?characters.

3.?public?List?parseRequest(javax.servlet.http.HttpServletRequest?req)

parseRequest?方法是ServletFileUpload類的重要方法,它是對HTTP請求消息體內容進行解析的入口
方法。
解析出FORM表單中的每個字段的數據,并將它們分別包裝成獨立的FileItem對象,然后將這
FileItem對象加入進一個List類型的集合對象中返回。

該方法拋出FileUploadException異常來處理諸如文件尺寸過大、請求消息中的實體內容的類型不
是“
multipart/form-data”、IO異常、請求消息體長度信息丟失等各種異常。每一種異常都是
FileUploadException的一個子類型。

4.?public?FileItemIterator?getItemIterator(HttpServletRequest?request)

getItemIterator方法和parseRequest?方法基本相同。但是getItemIterator方法返回的是一個迭代
器,該迭代器中保存的不是
FileItem對象,而是FileItemStream?對象,如果你希望進一步提高新能,
你可以采用?
getItemIterator?方法,直接獲得每一個文件項的數據輸入流,做底層處理;如果性能不
是問題,你希望代碼簡單,則采用
parseRequest方法即可。
?

5.?public?stiatc?boolean?isMultipartContent(HttpServletRequest?req)

isMultipartContent方法方法用于判斷請求消息中的內容是否是“multipart/form-data”類型,是則返
true,否則返回false
isMultipartContent方法是一個靜態方法,不用創建ServletFileUpload類的實例對
象即可被調用。

6.?getFileItemFactory()setFileItemFactory(FileItemFactory)方法

方法繼承自FileUpload類,用于設置和讀取fileItemFactory屬性。

7.?public?void?setProgressListener(ProgressListener?pListener)

設置文件上傳進度監聽器。關于監聽器的具體內容,將在后面學習。該方法有一個對應的讀取
方法:ProgressListener?getProgressListener()

8.public?void?setHeaderEncoding()方法

在文件上傳請求的消息體中,除了普通表單域的值是文本內容以外,文件上傳字段中的文件路
徑名也是文本,在內存中保存的是它們的某種字符集編碼的字節數組,Apache文件上傳組件在讀取
這些內容時,必須知道它們所采用的字符集編碼,才能將它們轉換成正確的字符文本返回。

setHeaderEncoding方法繼承自FileUploadBase類,用于設置上面提到的字符編碼。如果沒有設置,
則對應的讀方法g
etHeaderEncoding()方法返回null,將采用HttpServletRequest設置的字符編碼,如果
HttpServletRequest的字符編碼也為null,則采用系統默認字符編碼。可以通過一下語句獲得系統默認
字符編碼:

System.getProperty("file.encoding"));

好,到這里我們學習了主要的一些API,足夠我們來完成一個簡單文件上傳的功能了,下一章,
我們將一起來編寫一個文件上傳應用程序。

?

鄭州蜂鳥科技有限公司 申林 QQ:38185398? 鄭州軟件開發興趣小組群:38236716

學軟件開發,到蜂鳥科技!超強的師資力量 、完善的課程體系 、超低的培訓價格 、真實的企業項目。

地址:鄭州市文化路豐產路口東50米豐產路21號SOHO世紀城西塔20樓F?
電話:0371-63839606? 手機:13838505572(申老師) 13673990036 (許老師)
QQ: 1073422643? 1群:47614738 2群:108157678??
網址:www.ntcsoft.com

總結

以上是生活随笔為你收集整理的Java 文件上传组件 Apache Commons FileUpload 应用指南(二)——FileUpload如何工作?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。