java文件上傳技術(shù)深入剖析
本文實例為大家分享了java文件上傳技術(shù),供大家參考,具體內(nèi)容如下
表單:
客戶端發(fā)送HTTP必須使用multipart/form-data數(shù)據(jù)類型,表示復合數(shù)據(jù)類型。即:
在表單中使用html標簽。
需要的包:
Commons-fileupload.jar,核心上傳文件工具都在這個包中。
commons-io.jar – 上傳文件所需要的包
上傳文件類詳解:
DiskFileItemFactory-創(chuàng)建監(jiān)時文件目錄,指是緩存區(qū)大小
ServletFileUpload用于解析HttpServletRequest。返回一組文件對象。
FileItem – 表示用戶上傳的每一個文件對像。
<%@ 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文件上傳工具實現(xiàn)文件上傳</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文件上傳工具實現(xiàn)文件上傳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文件上傳工具實現(xiàn)文件上傳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>
過渡板–了解底層
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文件上傳工具實現(xiàn)文件上傳
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 { //在服務(wù)器上,為所有上傳文件指定一個存放目錄 String path=getServletContext().getRealPath("/upload"); System.out.println("path:"+path); File dir=new File(path); if(!dir.exists()){ dir.mkdirs(); } //創(chuàng)建一個基于硬盤的工廠 //DiskFileItemFactory disk = new DiskFileItemFactory(); //設(shè)置臨時目錄(建議設(shè)計臨時目錄,否則會使用系統(tǒng)臨時目錄。) //disk.setRepository(new File(“d:/a”)); //3、 設(shè)置向硬盤寫數(shù)據(jù)的緩沖區(qū)大小 disk.setSizeThreshold(1024*4);//當文件大于此設(shè)置時,將會在臨時目錄下形成臨時文件 //設(shè)置臨時文件緩沖區(qū)大小--8K緩沖,臨時文件地址 DiskFileItemFactory f=new DiskFileItemFactory(1024*8, new File("d:/a")); //上傳工具--創(chuàng)建用于解析的對像 ServletFileUpload upload=new ServletFileUpload(f); upload.setFileSizeMax(1024*1024*5);//設(shè)置上傳的單個文件最大為5M //設(shè)置上傳文件的最大大小,如果是多個文件,則為多個文件的和最大8M upload.setSizeMax(1024*1024*8);//設(shè)置所有上傳的文件大小之和最大為8M //使用解析工具解析 try { List<FileItem> list=upload.parseRequest(request); for(FileItem fI:list){ System.out.println("文件內(nèi)容類型:"+fI.getContentType());//文件內(nèi)容類型: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(); } } }
在這個地方存儲上傳的文件
上傳信息:
上傳結(jié)果:
使用apache文件上傳工具實現(xiàn)文件上傳2(解決文件名亂碼)
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),該劇只能設(shè)置所上傳文件的文件名中的編碼(解決他的中文亂碼) //但不能解決在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),下面這句可以設(shè)置普通表單組件內(nèi)容的編碼(能夠解決它們的中文亂碼問題) request.setCharacterEncoding("utf-8"); //如果是含上傳文件的表單(POST2),該句只能設(shè)置所上傳文件的文件名中的編碼(解決它的中文亂碼)。但不能解決普通表單組件的亂碼(不能設(shè)它編碼) //在服務(wù)器上,為所有上傳文件指定一個存放目錄 String path=getServletContext().getRealPath("/upload"); System.out.println("path:"+path); File dir=new File(path); if(!dir.exists()){ dir.mkdirs(); } //設(shè)置臨時文件緩沖區(qū)大小--8K緩沖,臨時文件地址 DiskFileItemFactory f=new DiskFileItemFactory(1024*8, new File("d:/a")); //上傳工具 ServletFileUpload upload=new ServletFileUpload(f); upload.setFileSizeMax(1024*1024*5);//設(shè)置上傳的單個文件最大為5M upload.setSizeMax(1024*1024*8);//設(shè)置所有上傳的文件大小之和最大為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"); //該句設(shè)置普通表單組件內(nèi)容編碼 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(); } } }
上傳信息:
上傳結(jié)果:
使用apache文件上傳工具實現(xiàn)文件上傳3(文件打散)
用Hash目錄優(yōu)化文件存儲:
Hash目錄是一種優(yōu)化文件存儲性能的方法。無論是Windows還是Linux,無論是NTFS還是ext3,每個目錄下所能容納的項目數(shù)是有限的。
并不是不能保存,而是當項目數(shù)量過大的時候,會降低文件索引速度,
所以權(quán)衡一個目錄下應(yīng)該保存多少文件是很必要的。保存得多了會影響性能,保存得少了會造成目錄太多和空間浪費。所以當保存大批文件的時候,
需要有一種算法能將文件比較均勻地“打散”在不同的子目錄下以提高每一級的索引速度,這種算法就是 Hash。通常用的MD5、sha1等都可以用來做Hash目錄,我的Session里也同樣使用了MD5,取得sessionID的第一位和第九位,這就構(gòu)成了兩級Hash路徑,也就是說,系統(tǒng)把所有的Session文件分散到了16×16=256個子目錄下。假設(shè)Linux每個目錄下保存1000個文件可以獲得最好的空間性能比,那么系統(tǒng)在理想情況下可以同時有256000個session文件在被使用。
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),該劇只能設(shè)置所上傳文件的文件名中的編碼(解決他的中文亂碼) //但不能解決在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),下面這句可以設(shè)置普通表單組件內(nèi)容的編碼(能夠解決它們的中文亂碼問題) request.setCharacterEncoding("utf-8"); //如果是含上傳文件的表單(POST2),該句只能設(shè)置所上傳文件的文件名中的編碼(解決它的中文亂碼)。但不能解決普通表單組件的亂碼(不能設(shè)它編碼) //在服務(wù)器上,為所有上傳文件指定一個存放目錄 String path=getServletContext().getRealPath("/upload"); System.out.println("path:"+path); File dir=new File(path); if(!dir.exists()){ dir.mkdirs(); } //設(shè)置臨時文件緩沖區(qū)大小--8K緩沖,臨時文件地址 DiskFileItemFactory f=new DiskFileItemFactory(1024*8, new File("d:/a")); //上傳工具 ServletFileUpload upload=new ServletFileUpload(f); upload.setFileSizeMax(1024*1024*5);//設(shè)置上傳的單個文件最大為5M upload.setSizeMax(1024*1024*8);//設(shè)置所有上傳的文件大小之和最大為8M //▲4上傳進度監(jiān)聽 upload.setProgressListener(new ProgressListener(){ private double pre=0D; @Override//參數(shù)1:已上傳多少字節(jié) 參數(shù)2:一共多少字節(jié) 參數(shù)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"); //該句設(shè)置普通表單組件內(nèi)容編碼 System.out.println("編碼后:"+desc); }else{ //防護:過濾掉沒選擇文件的空文件組件 if(fI.getSize()<=0){ continue;//讀下一個文件 } System.out.println("文件內(nèi)容類型:"+fI.getContentType());//文件內(nèi)容類型: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; //文件目錄打散技術(shù) 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(); } } }
打散信息:
打散結(jié)果:
文件1:
文件2:
演示上傳進度原理
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
實戰(zhàn)SpringBoot集成JWT實現(xiàn)token驗證
本文詳細講解了SpringBoot集成JWT實現(xiàn)token驗證,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-12-12spring boot使用WebClient調(diào)用HTTP服務(wù)代碼示例
這篇文章主要介紹了spring boot使用WebClient調(diào)用HTTP服務(wù)代碼示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-12-12詳解Spring Security中權(quán)限注解的使用
這篇文章主要為大家詳細介紹一下Spring Security中權(quán)限注解的使用方法,文中的示例代碼講解詳細,對我們學習或工作有一定參考價值,需要的可以參考一下2022-05-05Java關(guān)鍵字synchronized原理與鎖的狀態(tài)詳解
在Java當中synchronized關(guān)鍵字通常是用來標記一個方法或者代碼塊。本文將通過示例為大家詳細介紹一下Synchronized的各種使用方法,需要的可以參考一下2022-08-08Java實現(xiàn)的質(zhì)因數(shù)分解操作示例【基于遞歸算法】
這篇文章主要介紹了Java實現(xiàn)的質(zhì)因數(shù)分解操作,結(jié)合實例形式較為詳細的分析了Java基于遞歸算法實現(xiàn)針對整數(shù)的質(zhì)因數(shù)分解相關(guān)操作技巧,需要的朋友可以參考下2018-03-03Java數(shù)據(jù)結(jié)構(gòu)之加權(quán)無向圖的設(shè)計實現(xiàn)
加權(quán)無向圖是一種為每條邊關(guān)聯(lián)一個權(quán)重值或是成本的圖模型。這種圖能夠自然地表示許多應(yīng)用。這篇文章主要介紹了加權(quán)無向圖的設(shè)計與實現(xiàn),感興趣的可以了解一下2022-11-11詳解 Java繼承關(guān)系下的構(gòu)造方法調(diào)用
這篇文章主要介紹了詳解 Java繼承關(guān)系下的構(gòu)造方法調(diào)用的相關(guān)資料,希望通過本文能幫助到大家,讓大家理解掌握這部分內(nèi)容,需要的朋友可以參考下2017-10-10