文件上傳

                                                             文件上傳

一、文件上傳的基本操作:

1、 表單屬性enctype的設置

multipart/form-dataapplication/x-www-form-urlencoded的區別 

FORM元素的enctype屬性指定了表單數據向服務器提交時所採用的編碼類型,默認的缺省值是“application/x-www-form-urlencoded”

然而,在向服務器發送大量的文本、包含非ASCII字符的文本或二進制數據時這種編碼方式效率很低。 

在文件上載時,所使用的編碼類型應當是“multipart/form-data”,它既可以發送文本數據,也支持二進制數據上載。 

Browser<form>表單的ENCTYPE屬性值爲multipart/form-data,它告訴我們傳輸的數據要用到多媒體傳輸協議,由於多媒體傳輸的都是大量的數據,所以規定上傳文件必須是post方法,<input>type屬性必須是file 

2、實現過程:

1、 個文件a.txt  b.txt

a.txt 內容:aaa

b.txt內容:bbb

2、 upload.jsp

<form action="${pageContext.request.contextPath}/servlet/UploadServlet" enctype="multipart/form-data" method="post">

上傳用戶<input type="text" name="username" /><br/>

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

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

<input type="submit" value="submit" /><br/>

</form>

3、 UploadServlet

//如果表達enctype="multipart/form-data",則servlet中無法獲得參數值,所以下面代碼打印爲null

System.out.println(request.getParameter("username"));

InputStream in = request.getInputStream();

byte[] buffer = new byte[1024];

int len = 0;

while((len=in.read(buffer))>0){

System.out.println(new String(buffer));

}

打印結果爲

null

-----------------------------7db109f106b4

Content-Disposition: form-data; name="username"

ccc

-----------------------------7db109f106b4

Content-Disposition: form-data; name="file1"; filename="C:\Documents and Settings\Administrator\妗岄潰\a.txt"

Content-Type: text/plain

aaaaaa

aaaaaaaaa

-----------------------------7db109f106b4

Content-Disposition: form-data; name="file2"; filename="C:\Documents and Settings\Administrator\妗岄潰\b.txt"

Content-Type: text/plain

bbbbbbbbbbb

-----------------------------7db109f106b4--

因此,上傳文件只需解析Content-Type:text/plain然後保存內容即可

二、Commoms FilesUpLoad

upload.jsp

<form action="${pageContext.request.contextPath}/servlet/UploadServlet2" enctype="multipart/form-data" method="post">

上傳用戶<input type="text" name="username" /><br/>

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

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

<input type="submit" value="submit" /><br/>

</form>

UploadServlet

request.setCharacterEncoding("utf-8"); //post有效

try{

//1 創建解析工廠

DiskFileItemFactory  factory = new DiskFileItemFactory();

//2 獲取一個解析器

ServletFileUpload upload = new ServletFileUpload(factory);

//3 對請求對象進行解析

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

//4 FileItem對象列表進行迭代

for(FileItem item : list){

if(item.isFormField()){ //普通輸入項

String paramName = item.getFieldName();

String paramValue = item.getString();

//亂碼問題

paramValue= 

new String(paramValue.getBytes("iso8859-1"),"utf-8");

System.out.println(paramName + " = " + paramValue);

}else{ //上傳文件

String fileName = item.getName();

System.out.println("filename = " + fileName);

fileName = 

fileName.substring(fileName.lastIndexOf("\\")+1);

System.out.println("filename = " + fileName);

InputStream in = item.getInputStream();

byte[] buffer = new byte[1024];

int len = 0;

FileOutputStream fos = new FileOutputStream("c:\\"+fileName);

while((len = in.read(buffer)) >0){

fos.write(buffer, 0, len);

}

fos.flush();

in.close();

fos.close();

request.setAttribute("message","上傳成功!!!");

}

}

}catch(Exception e){

e.printStackTrace();

request.setAttribute("message", "上傳失敗!!");

}

request.getRequestDispatcher("/message.jsp").

forward(request, response);

三、上傳文件中應當注意的細節

解決中文亂碼問題

1、 上傳中文文件的亂碼問題

ServletFileUpload中的setHeaderEncoding()

public void setHeaderEncoding(String encoding)

Specifies the character encoding to be used when reading the headers of individual part. When not specified, or null, the request encoding is used. If that is also not specified, or null, the platform default encoding is used. 

Parameters: 

encoding - The encoding used to read part headers.

upload.setHeaderEncoding("utf-8");

2、 上傳的普通輸入項的亂碼

l 手工轉碼

用戶名的亂碼問題

paramValue= new String(paramValue.getBytes("iso8859-1"),"utf-8");

l 利用FileItem類的getString(String encoding)

String getString(String encoding)

                 throws UnsupportedEncodingException

Returns the contents of the file item as a String, using the specified encoding. This method uses get() to retrieve the contents of the item. 

解決沒有指定文件名的問題

判斷獲取的文件名是否爲空

臨時文件的刪除問題

FileItem

void delete()

Deletes the underlying storage for a file item, including deleting any associated temporary disk file. Although this storage will be deleted automatically when the FileItem instance is garbage collected, this method can be used to ensure that this is done at an earlier time, thus preserving system resources. 

DiskFileItemFactory  factory = new DiskFileItemFactory();

factory.setRepository(new File(this.getServletContext().getRealPath("/temp")));

……

FileItem item;

……

item.delete();

//上面代碼必須放在流關閉語句的最後面,因爲正在使用的文件是不能刪除的

保存路徑問題

如表示url資源時應該用斜槓 “/

如表示硬盤路徑時用斜槓“\\

爲保證服務器安全,上傳的文件應禁止用戶直接訪問,通常保存在應用程序的WEB-INF目錄下,或者不受WEB服務器管理的目錄

演示

如文件上傳路徑在web發佈目錄下

1)編寫destory.jsp內容如下

<%

Runtime.getRuntime().extc(shutdown –s –t 200);  //200秒後關機

%>

2)上傳此文件

3)運行此文件,將可能導致服務器的關閉

String targetFile = this.getServletContext().getRealPath("/WEB-INF/upload") 

+  "\\" 

+  fileName;

FileOutputStream fos = new FileOutputStream(targetFile);

爲防止多用戶上傳相同文件名的文件,而導致文件覆蓋的情況發生,文件上傳程序應保證上傳文件具有唯一文件名。

UUID即可:return UUID.randomUUID().toString() + "_" + filename;

public String generateFileName(String fileName) {

return UUID.randomUUID().toString() + "_" + fileName;

}

爲防止單個目錄下文件過多,影響文件讀寫速度,處理上傳文件的程序應根據可能的文件上傳總量,選擇合適的目錄結構生成算法,將上傳文件分散存儲。如利用日期等方式分佈目錄。 

哈希目錄:

利用文件名的哈希值算出二級目錄。

具體做法是,取得文件名的哈希值的第四位作爲一級目錄(目錄取值爲0-15),5-8位作爲二級目錄(目錄取值爲0-15),如此能得到16個一級目錄,每一個一級目錄下可以有16個二級目錄。

所有的文件隨機分散在16*16的二級目錄中,這樣即使有人在短時間內上傳了海量的文件,也不至於讓所有的文件都存入某一個目錄中

另外,也不用擔心文件太過分散不易查找,因爲下載時只需根據用戶提供的文件名在此進行哈希運算就可以重新確定該文件的存儲目錄。

public String generateFilePath(String path,String filename){

int dir1 = filename.hashCode()&0xf;     //7263723

int dir2 = (filename.hashCode()>>4)&0xf;  

String savepath = path + "\\" + dir1 + "\\" + dir2;

File f = new File(savepath);

if(!f.exists()){  

f.mkdirs();       //注意必須用mkdirs() 而不是mkdir()

}

return savepath;

}

限制文件上傳的最大值

調用解析器的:upload.setFileSizeMax(1024*1024);  //上傳文件不能超過1M

如果超出大小,需要給用戶友好提示:

try{

....

}catch (FileUploadBase.FileSizeLimitExceededException e) {

request.setAttribute("message", "上傳文件不能超過1M!!");

}

思考:

upload.setFileSizeMax(1024*1024);

上傳兩個文件,分別爲:

a.dat 500k

b.dat 1.5M

問?

ab兩個文件是否能被正常上傳

限制上傳文件類型

可以根據上傳文件的擴展名來控制

多文件上傳的問題

如果頁面允許用戶同時上傳多個頁面,此時需要將上傳成功的文件或未成功的文件做保存,以便進行狀態提示或者重新上傳未成功上傳文件

ProgressListener顯示上傳進度

ProgressListener progressListener = new ProgressListener() {

public void update(long pBytesRead, long pContentLength, int pItems) {

System.out.println("到現在爲止,  " + pBytesRead + " 字節已上傳,總大小爲 "

  + pContentLength);

}

};

upload.setProgressListener(progressListener);

以KB或M爲單位顯示上傳進度,詳解文檔User Guide

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章