亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

Apache FileUpload 文件上傳組件API解讀-2

2019-11-11 03:29:53
字體:
來源:轉載
供稿:網友

1.RFC1867協議

最初的 http 協議中,沒有上傳文件方面的功能。RFC1867("Form-based File Upload in HTML".)

為 http 協議添加了這個功能??蛻舳说臑g覽器,如 Microsoft IE, Mozila, Opera 等,按照此規范將用戶指定的文件發送到服務器。服務器端的網頁程序,如 phpaspjsp 等,可以按照此規范,解析出用戶發送來的文件。

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接口的對象,并以列表的形式返回。所以,我們只需要了解FileUpload的API如何使用即可,不用管它們的底層實現。讓我們來看一個簡單文件上傳處理代碼:

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-Flashapplication/msWordapplication/vnd.ms-Excelapplication/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類

將請求消息實體中的每一個項目封裝成單獨的 (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相關配置將每一個請求消息實體項目創建 成 實例,并返回。該方法從來不需要我們親自調用,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類,用于設置上面提到的字符編碼。如果沒有設置,則對應的讀方法getHeaderEncoding()方法返回null,將采用HttpServletRequest設置的字符編碼,如果HttpServletRequest的字符編碼也為null,則采用系統默認字符編碼。可以通過一下語句獲得系統默認字符編碼:

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


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美日韩国产123| 91精品在线一区| 久久精品中文字幕电影| 国产精品美女免费视频| 色先锋资源久久综合5566| 丝袜情趣国产精品| 这里精品视频免费| 亚洲黄页网在线观看| 精品视频久久久久久久| 九九视频直播综合网| 欧美精品videosex牲欧美| 久久久精品视频在线观看| 国产精品丝袜一区二区三区| 自拍偷拍亚洲在线| 久久色精品视频| 欧美日韩一区二区三区在线免费观看| 亚洲欧美成人一区二区在线电影| 高清一区二区三区四区五区| 日韩免费不卡av| 国内精品小视频| 韩国日本不卡在线| 亲子乱一区二区三区电影| 亚州av一区二区| 中文字幕九色91在线| 一区二区三区四区在线观看视频| 久久精品国产69国产精品亚洲| 日韩中文在线视频| 91欧美精品午夜性色福利在线| 亚洲另类xxxx| 日本精品久久久久久久| 欧美性xxxxx极品| 性欧美在线看片a免费观看| 国产日韩中文字幕| 亚洲一区二区三区777| 国产成人精品久久亚洲高清不卡| 国产精品黄色影片导航在线观看| 日韩av电影国产| 亚洲aⅴ男人的天堂在线观看| 亚洲free嫩bbb| 日韩av电影手机在线| 中文字幕日韩在线播放| 久久伊人精品天天| 91精品国产高清久久久久久久久| 欧美猛少妇色xxxxx| 久久久中精品2020中文| 欧美日韩在线视频首页| 色综合91久久精品中文字幕| 最新亚洲国产精品| 日本国产精品视频| 社区色欧美激情 | 亚洲精品国产精品乱码不99按摩| 欧美日韩亚洲一区二区| 亚洲黄色av女优在线观看| 亚洲福利小视频| 亚洲日本中文字幕免费在线不卡| 国产精品久久久久久久一区探花| 国产欧美精品日韩| 日韩精品久久久久久福利| 欧美日韩国产一中文字不卡| 欧美日韩免费区域视频在线观看| 亚洲免费小视频| 2020久久国产精品| 国产精品福利无圣光在线一区| 国产成人涩涩涩视频在线观看| 亚洲天堂网在线观看| 91在线无精精品一区二区| 91久久精品美女高潮| 日韩美女毛茸茸| 欧美成人精品一区二区三区| 中文字幕亚洲二区| 九九久久综合网站| 九色91av视频| 欧美精品videossex性护士| 国产精品久久久久久久久粉嫩av| 亚洲一区二区免费| 久久久久久97| 国产精品第1页| 另类视频在线观看| 国产精品1234| 亚洲自拍偷拍色片视频| 日韩久久免费电影| 日韩av在线免费观看| 亚洲激情在线视频| 国产精品久久久久久婷婷天堂| 日韩中文字幕视频| 成人免费观看49www在线观看| 色综合久久中文字幕综合网小说| 欧美另类在线播放| 午夜精品美女自拍福到在线| 国产成人高清激情视频在线观看| 国产香蕉97碰碰久久人人| 热久久99这里有精品| 久久影视三级福利片| 91大神在线播放精品| 日韩视频第一页| 精品国产福利视频| 亚洲日本aⅴ片在线观看香蕉| 亚洲精品视频网上网址在线观看| 久久久精品2019中文字幕神马| 38少妇精品导航| 欧美国产在线视频| 日韩欧美中文在线| 最近日韩中文字幕中文| 国产97免费视| 午夜免费日韩视频| 国产精品三级网站| 国产精品99蜜臀久久不卡二区| 91九色视频导航| 在线电影欧美日韩一区二区私密| 亚洲欧美日韩图片| 成人黄色片在线| 青草青草久热精品视频在线观看| 亚洲欧洲日韩国产| 亚洲字幕在线观看| 日韩在线观看av| 日韩精品在线观看一区二区| 亚洲电影免费观看高清| 欧美激情久久久| 日韩精品亚洲精品| 色综合久久天天综线观看| 欧美风情在线观看| 欧美一级免费看| 久久亚洲一区二区三区四区五区高| 日韩视频免费在线观看| 粉嫩av一区二区三区免费野| 日韩中文字幕精品| 亚洲四色影视在线观看| 最近2019免费中文字幕视频三| 亚洲视频电影图片偷拍一区| 久久伊人精品一区二区三区| 日韩精品极品在线观看| 亚洲欧美精品中文字幕在线| 欧美激情一区二区久久久| 欧美日韩国产区| 欧美大片免费看| 另类天堂视频在线观看| 日韩电影免费在线观看中文字幕| 成人深夜直播免费观看| 中文字幕久久久av一区| 国产欧美日韩精品在线观看| 91九色国产在线| 51色欧美片视频在线观看| 精品一区二区三区四区在线| 欧美成人免费大片| 国产精品久久久久久久久久久新郎| 欧美日韩国产精品| 欧美日韩综合视频| 国产精品自拍网| 日韩欧美一区二区在线| 色香阁99久久精品久久久| 成人精品一区二区三区| 亚洲香蕉成人av网站在线观看| 精品女同一区二区三区在线播放| 国产精品久久久久久超碰| 日韩av网站电影| 亚洲一区二区中文| 一区二区三区四区在线观看视频| 色综合视频网站| 欧美最猛性xxxxx免费| 国产成人精品久久二区二区| 色噜噜狠狠狠综合曰曰曰88av| 麻豆乱码国产一区二区三区| 国产日韩精品综合网站| 国产视频精品久久久|