java文件上传技术深入剖析
本文实例为大家分享了java文件上传技术,供大家参考,具体内容如下
表单:
客户端发送http必须使用multipart/form-data数据类型,表示复合数据类型。即:
在表单中使用html标签。
需要的包:
commons-fileupload.jar,核心上传文件工具都在这个包中。
commons-io.jar – 上传文件所需要的包
上传文件类详解:
diskfileitemfactory-创建监时文件目录,指是缓存区大小
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文件上传工具实现文件上传</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>
过渡板–了解底层
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文件上传工具实现文件上传
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(解决文件名乱码)
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文件在被使用。
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:
演示上传进度原理
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: Java中统计字符串中字符出现的次数