本文實例為大家分享了java文件上傳技術,供大家參考,具體內容如下
表單:
客戶端發送HTTP必須使用multipart/form-data數據類型,表示復合數據類型。即:
在表單中使用html標簽。
需要的包:
Commons-fileupload.jar,核心上傳文件工具都在這個包中。
commons-io.jar – 上傳文件所需要的包
上傳文件類詳解:
DiskFileItemFactory-創建監時文件目錄,指是緩存區大小
ServletFileUpload用于解析HttpServletRequest。返回一組文件對象。
FileItem – 表示用戶上傳的每一個文件對像。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> < html > < head > < title >文件上傳演示</ title > </ head > < body > < font color = "red" size = "6" >過渡板--了解底層</ font > <!-- multipart/form-data:多部分(不但有文件,也有部分) --> < form action="<%=request.getContextPath()%>/upload0" method="post" enctype="multipart/form-data"> 文件:< input type = "file" name = "file" /> < input type = "submit" value = "上傳" /> <!-- 上傳的文件名不能為中文,否則獲取的文件名是亂碼,不過下面的例子可以解決這個問題 --> </ form > < br /> < font color = "red" size = "6" >使用apache文件上傳工具實現文件上傳</ font > <!-- application/x-www-form-urlencoded --> < form action="<%=request.getContextPath()%>/upload" method="post" enctype="multipart/form-data"> 文件:< input type = "file" name = "file" /> < input type = "submit" value = "上傳" /> </ form > < font color = "red" size = "6" >使用apache文件上傳工具實現文件上傳2(解決文件名亂碼)</ font > < p > POST1(普通表單):enctype=application/x-www-form-urlencoded(默認值) </ p > < p > POST2(上傳文件表單):enctype=multipart/form-data:多部分(不但有文件,也有部分) </ p > < form action="<%=request.getContextPath()%>/upload2" method="post" enctype="multipart/form-data"> 文件:< input type = "file" name = "file" /> <!-- POST2(上傳文件表單) --> < br /> 文件說明:< input type = "text" name = "desc" /> <!-- POST1(普通表單) --> < br />< br /> 文件2:< input type = "file" name = "file" />< br /> 文件說明2:< input type = "text" name = "desc" /> < input type = "submit" value = "上傳" /> </ form > < font color = "red" size = "6" >使用apache文件上傳工具實現文件上傳3(文件打散)</ font > <!-- POST1(普通表單):enctype=application/x-www-form-urlencoded(默認值) --> <!-- POST2(上傳文件表單):enctype=multipart/form-data:多部分(不但有文件,也有部分) --> < form action="<%=request.getContextPath()%>/upload3" method="post" enctype="multipart/form-data"> 文件:< input type = "file" name = "file" /> <!-- POST2(上傳文件表單) --> < br /> 文件說明:< input type = "text" name = "desc" /> <!-- POST1(普通表單) --> < br />< br /> 文件2:< input type = "file" name = "file" />< br /> 文件說明2:< input type = "text" name = "desc" /> < input type = "submit" value = "上傳" /> </ form > </ body > </ html > |
過渡板–了解底層
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
package cn.hncu.servlet; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Upload0Servlet extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { InputStream in=request.getInputStream(); BufferedReader br= new BufferedReader( new InputStreamReader(in)); String line; while ((line=br.readLine())!= null ){ System.out.println(line); } } } |
使用apache文件上傳工具實現文件上傳
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
package cn.hncu.servlet; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.List; import java.util.UUID; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.io.FileUtils; public class UploadServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType( "text/html" ); PrintWriter out = response.getWriter(); out.println( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">" ); out.println( "<HTML>" ); out.println( " <HEAD><TITLE>A Servlet</TITLE></HEAD>" ); out.println( " <BODY>" ); out.print( "不支持Get方式上傳。。。。。。" ); out.println( " </BODY>" ); out.println( "</HTML>" ); out.flush(); out.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //在服務器上,為所有上傳文件指定一個存放目錄 String path=getServletContext().getRealPath( "/upload" ); System.out.println( "path:" +path); File dir= new File(path); if (!dir.exists()){ dir.mkdirs(); } //創建一個基于硬盤的工廠 //DiskFileItemFactory disk = new DiskFileItemFactory(); //設置臨時目錄(建議設計臨時目錄,否則會使用系統臨時目錄。) //disk.setRepository(new File(“d:/a”)); //3、 設置向硬盤寫數據的緩沖區大小 disk.setSizeThreshold( 1024 * 4 ); //當文件大于此設置時,將會在臨時目錄下形成臨時文件 //設置臨時文件緩沖區大小--8K緩沖,臨時文件地址 DiskFileItemFactory f= new DiskFileItemFactory( 1024 * 8 , new File( "d:/a" )); //上傳工具--創建用于解析的對像 ServletFileUpload upload= new ServletFileUpload(f); upload.setFileSizeMax( 1024 * 1024 * 5 ); //設置上傳的單個文件最大為5M //設置上傳文件的最大大小,如果是多個文件,則為多個文件的和最大8M upload.setSizeMax( 1024 * 1024 * 8 ); //設置所有上傳的文件大小之和最大為8M //使用解析工具解析 try { List<FileItem> list=upload.parseRequest(request); for (FileItem fI:list){ System.out.println( "文件內容類型:" +fI.getContentType()); //文件內容類型:text/plain System.out.println( "文件名:" +fI.getName()); //文件名:C:\Users\adl1\Desktop\a.txt String ext=fI.getName().substring(fI.getName().lastIndexOf( "." )); //.txt String uuid=UUID.randomUUID().toString().replace( "-" , "" ); String fileName=uuid+ext; // FileUtils.copyInputStreamToFile(fI.getInputStream(), new File("d:/a/d/a.txt"));//寫死了 //fI.getInputStream()是真正文件信息 FileUtils.copyInputStreamToFile(fI.getInputStream(), new File(path+ "/" +fileName)); //寫活了 } } catch (FileUploadException e) { e.printStackTrace(); } } } |
在這個地方存儲上傳的文件
上傳信息:
上傳結果:
使用apache文件上傳工具實現文件上傳2(解決文件名亂碼)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
package cn.hncu.servlet; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.List; import java.util.UUID; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.io.FileUtils; public class Upload2Servlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType( "text/html" ); //如果是含上傳文件的表單(POST2),該劇只能設置所上傳文件的文件名中的編碼(解決他的中文亂碼) //但不能解決在POST2方式下的普通表單組件的中文亂碼 PrintWriter out = response.getWriter(); out.println( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">" ); out.println( "<HTML>" ); out.println( " <HEAD><TITLE>A Servlet</TITLE></HEAD>" ); out.println( " <BODY>" ); out.print( "不支持Get方式上傳。。。。。。" ); out.println( " </BODY>" ); out.println( "</HTML>" ); out.flush(); out.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //第一步 //普通的form表單(POST1),下面這句可以設置普通表單組件內容的編碼(能夠解決它們的中文亂碼問題) request.setCharacterEncoding( "utf-8" ); //如果是含上傳文件的表單(POST2),該句只能設置所上傳文件的文件名中的編碼(解決它的中文亂碼)。但不能解決普通表單組件的亂碼(不能設它編碼) //在服務器上,為所有上傳文件指定一個存放目錄 String path=getServletContext().getRealPath( "/upload" ); System.out.println( "path:" +path); File dir= new File(path); if (!dir.exists()){ dir.mkdirs(); } //設置臨時文件緩沖區大小--8K緩沖,臨時文件地址 DiskFileItemFactory f= new DiskFileItemFactory( 1024 * 8 , new File( "d:/a" )); //上傳工具 ServletFileUpload upload= new ServletFileUpload(f); upload.setFileSizeMax( 1024 * 1024 * 5 ); //設置上傳的單個文件最大為5M upload.setSizeMax( 1024 * 1024 * 8 ); //設置所有上傳的文件大小之和最大為8M //使用解析工具解析 try { List<FileItem> list=upload.parseRequest(request); for (FileItem fI:list){ if ((fI.isFormField())){ //如果是普通表單組件:checkbox,radio,password... // String desc=fI.getString(); System.out.println( "fI.getString():" +fI.getString()); //第二步 String desc=fI.getString( "utf-8" ); //該句設置普通表單組件內容編碼 System.out.println( "編碼后:" +desc); } else { String ext=fI.getName().substring(fI.getName().lastIndexOf( "." )); //.txt String uuid=UUID.randomUUID().toString().replace( "-" , "" ); String fileName=uuid+ext; //fI.getInputStream()是真正文件信息 FileUtils.copyInputStreamToFile(fI.getInputStream(), new File(path+ "/" +fileName)); //寫活了 } } } catch (FileUploadException e) { e.printStackTrace(); } } } |
上傳信息:
上傳結果:
使用apache文件上傳工具實現文件上傳3(文件打散)
用Hash目錄優化文件存儲:
Hash目錄是一種優化文件存儲性能的方法。無論是Windows還是Linux,無論是NTFS還是ext3,每個目錄下所能容納的項目數是有限的。
并不是不能保存,而是當項目數量過大的時候,會降低文件索引速度,
所以權衡一個目錄下應該保存多少文件是很必要的。保存得多了會影響性能,保存得少了會造成目錄太多和空間浪費。所以當保存大批文件的時候,
需要有一種算法能將文件比較均勻地“打散”在不同的子目錄下以提高每一級的索引速度,這種算法就是 Hash。通常用的MD5、sha1等都可以用來做Hash目錄,我的Session里也同樣使用了MD5,取得sessionID的第一位和第九位,這就構成了兩級Hash路徑,也就是說,系統把所有的Session文件分散到了16×16=256個子目錄下。假設Linux每個目錄下保存1000個文件可以獲得最好的空間性能比,那么系統在理想情況下可以同時有256000個session文件在被使用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
package cn.hncu.servlet; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.List; import java.util.UUID; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.ProgressListener; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.io.FileUtils; public class Upload3Servlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType( "text/html" ); //如果是含上傳文件的表單(POST2),該劇只能設置所上傳文件的文件名中的編碼(解決他的中文亂碼) //但不能解決在POST2方式下的普通表單組件的中文亂碼 PrintWriter out = response.getWriter(); out.println( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">" ); out.println( "<HTML>" ); out.println( " <HEAD><TITLE>A Servlet</TITLE></HEAD>" ); out.println( " <BODY>" ); //獲取GET方式的url中“?”號后面的部分 //http://localhost:8080/servletDemo3/upload?name=Jack&sex=male String qStr = request.getQueryString(); System.out.println( "qStr: " +qStr); //qStr: name=Jack&sex=male out.print( "不支持Get方式上傳。。。。。。" ); out.println( " </BODY>" ); out.println( "</HTML>" ); out.flush(); out.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType( "text/html;charset=utf-8" ); PrintWriter out = response.getWriter(); //1防黑: 防護前端采用POST1方式提交 //法1 /* String type=request.getContentType(); if(!type.contains("multipart/form-data")){ out.println("不支持普通表單提交"); return; }*/ //法2 boolean boo = ServletFileUpload.isMultipartContent(request); if (!boo){ out.println( "不支持普通表單提交" ); return ; } //第一步 //普通的form表單(POST1),下面這句可以設置普通表單組件內容的編碼(能夠解決它們的中文亂碼問題) request.setCharacterEncoding( "utf-8" ); //如果是含上傳文件的表單(POST2),該句只能設置所上傳文件的文件名中的編碼(解決它的中文亂碼)。但不能解決普通表單組件的亂碼(不能設它編碼) //在服務器上,為所有上傳文件指定一個存放目錄 String path=getServletContext().getRealPath( "/upload" ); System.out.println( "path:" +path); File dir= new File(path); if (!dir.exists()){ dir.mkdirs(); } //設置臨時文件緩沖區大小--8K緩沖,臨時文件地址 DiskFileItemFactory f= new DiskFileItemFactory( 1024 * 8 , new File( "d:/a" )); //上傳工具 ServletFileUpload upload= new ServletFileUpload(f); upload.setFileSizeMax( 1024 * 1024 * 5 ); //設置上傳的單個文件最大為5M upload.setSizeMax( 1024 * 1024 * 8 ); //設置所有上傳的文件大小之和最大為8M //▲4上傳進度監聽 upload.setProgressListener( new ProgressListener(){ private double pre=0D; @Override //參數1:已上傳多少字節 參數2:一共多少字節 參數3:第幾個文件(序號從1開始) public void update( long pByteRead, long pContentLength, int pItems) { double d = 1.0 *pByteRead/pContentLength* 100 ; System.out.println(d+ "%" ); if (pre!=d){ System.out.println(d+ "%" ); pre=d; } } }); //使用解析工具解析 try { List<FileItem> list=upload.parseRequest(request); for (FileItem fI:list){ if ((fI.isFormField())){ //如果是普通表單組件:checkbox,radio,password... // String desc=fI.getString(); System.out.println( "fI.getString():" +fI.getString()); //第二步 String desc=fI.getString( "utf-8" ); //該句設置普通表單組件內容編碼 System.out.println( "編碼后:" +desc); } else { //防護:過濾掉沒選擇文件的空文件組件 if (fI.getSize()<= 0 ){ continue ; //讀下一個文件 } System.out.println( "文件內容類型:" +fI.getContentType()); //文件內容類型:text/plain System.out.println( "文件名:" +fI.getName()); //文件名:C:\Users\adl1\Desktop\a.txt String ext=fI.getName().substring(fI.getName().lastIndexOf( "." )); //.txt String uuid=UUID.randomUUID().toString().replace( "-" , "" ); String fileName=uuid+ext; //文件目錄打散技術 String dir1=Integer.toHexString(uuid.hashCode()& 0x0f ); String dir2=Integer.toHexString((uuid.hashCode()& 0xf0 )>> 4 ); //fI.getInputStream()是真正文件信息 FileUtils.copyInputStreamToFile(fI.getInputStream(), new File(path+ "/" +dir1+ "/" +dir2+ "/" +fileName)); //寫活了 } } } catch (FileUploadException e) { e.printStackTrace(); } } } |
打散信息:
打散結果:
文件1:
文件2:
演示上傳進度原理
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。