sinobuy
  

你好! 访客. 请先 登陆注册一个帐号.
十月 23, 2019, 01:23:24 am
论文答辩趣闻 新年祝福短信 淘淘成长日记 可爱发行全攻略 鬼故事一箩筐 杨柳青石家大院 淘淘成长日记
* 首页 说明 搜索 日历 登陆 注册
公告和新闻:原生态购物网沉香微店热卖 点击进入
原生态论坛  |  设计专版  |  网页/程序设计 (版主: tianya)  |  主题: java---文件上传/打散目录/进度条 0 会员 以及 1 访客 正在阅读本篇主题. « 上一篇主题 下一篇主题 »
页: [1] 向下 打印
作者 主题: java---文件上传/打散目录/进度条  (阅读 438 次)
水影凝月
Administrator(管理员)
级别:东方不败
*****

受欢迎度: 190
在线 在线

帖子: 23119


451314485
个人网站 电子邮件
java---文件上传/打散目录/进度条
« 于: 九月 05, 2016, 10:37:08 am »

此文标题提到的三个功能其实都是可以整合在一起的,于是我就写在了同一段代码中了。

先还是老规矩:index.jsp

   
程序代码:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 
     
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
    <html> 
      <head> 
      </head> 
       
      <body> 
        <form action="<%=request.getContextPath() %>/upload2" method="post" enctype="multipart/form-data"> 
            文件1:<input type="file" name="file" /><br/> 
            文件1的说明:<input type="text" name="desc1"/><br/> 
            文件2:<input type="file" name="file" /><br/> 
            文件2的说明:<input type="text" name="desc2"/><br/> 
            <input type="submit" value="提交" /> 
        </form> 
      </body> 
    </html> 

然后是正文了:UploadServlet2.java

程序代码:
    package cn.hncu.servlets.upload; 
     
    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; 
     
    public class UploadServlet2 extends HttpServlet { 
         
        //☆防黑1--在地址栏直接提交 
        public void doGet(HttpServletRequest request, HttpServletResponse response) 
                throws ServletException, IOException { 
            response.setContentType("text/html;charset=utf-8"); 
            response.getWriter().print("不支持get方式上传!!"); 
        } 
         
        public void doPost(HttpServletRequest request, HttpServletResponse response) 
                throws ServletException, IOException { 
            response.setContentType("text/html;charset=utf-8"); 
            final PrintWriter out=response.getWriter(); 
             
            //☆防黑2--非multipart表单提交 
            /*手动方式
            String type=request.getContentType();
            if (!type.contains("multipart/form-data")){
                out.print("不支持普通表单提交!");
                return;
            }
            */ 
            //使用上传工具的方式 
            boolean boo=ServletFileUpload.isMultipartContent(request); 
            if (!boo){ 
                out.print("不支持普通表单提交!"); 
                return; 
            } 
             
            //缓冲文件 
            DiskFileItemFactory factory=new DiskFileItemFactory(); 
            factory.setSizeThreshold(1024*8); 
            factory.setRepository(new File("d:/a/b"));//文件上传需要临时目录(如果不指定,那么该目录就是tomcat/temp ) 
            /*
             上面三句其实就相当于下面两句
             File tempDir=new File("d:/a/b");
             DiskFileItemFactory fileFactory=new DiskFileItemFactory(1024*8, tempDir);//创建用于解析文件的工厂类,同时设置缓冲区的位置和大小
             */ 
            ServletFileUpload upload=new ServletFileUpload(factory); 
            upload.setHeaderEncoding("utf-8");//用于设置文件名的编码,相当于:request.setCharacterEncoding("utf-8"); 
            String path=getServletContext().getRealPath("/imgs");//获取所接收文件要保存的路径 
             
            //☆文件上传进度功能---设置监听器 
            upload.setProgressListener(new ProgressListener() { 
                private int pre=0; 
                //参数解析---- pBytesRead:已上传字节数   pContentLength:上传的总字节数   pItems:文件序号(从1开始的) 
                @Override 
                public void update(long pBytesRead, long pContentLength, int pItems) { 
                    double p=pBytesRead*100.0/pContentLength;//上传的总字节数 
                    int pp=(int) p; 
                    if (pre!=pp){ 
                        out.print(pp+"%<br/>"); 
                        pre=pp; 
                    } 
                } 
            }); 
             
            FileItem fi=null; 
            try { 
                List<FileItem> list=upload.parseRequest(request); 
                for (FileItem fi2:list){ 
                    fi=fi2; 
                    if (fi.isFormField()){//普通表单组件,如:<input type="text" name="desc1"/> 
                        String str=fi.getString("utf-8");//※以指定编码的方式获取,来解决普通表单组件的中文乱码问题 
                        System.out.println("普通表单组件提交的内容:"+str); 
                    } else {//表单中的:file组件 
                        //☆防黑3--在file组件中不选择文件 
                        if (fi.getSize()==0){ 
                            continue; 
                        } 
                         
                        //文件名 
                        String fileName=fi.getName(); 
                        fileName=fileName.substring(fileName.lastIndexOf("/")+1); 
                        String ext=fileName.substring(fileName.lastIndexOf(".")); 
                        //文件名不能用中文,必须转换成ascii码的格式,而且文件名不能重复(必须保证唯一),因此采用UUID来实现 
                        String newFileName=UUID.randomUUID().toString().replace("-", "")+ext; 
                         
                        //☆打散目录(因为对于普通机器,一个文件夹如果存储的文件个数超过1000,性能将会急剧下降!! ) 
                        String dir1=Integer.toHexString((fileName.hashCode()) & 0xf);//一级目录 
                        String dir2=Integer.toHexString(((fileName.hashCode()) & 0xf0)>>4);//二级目录 
                        File dir=new File(path+"/"+dir1+"/"+dir2); 
                        if (!dir.exists()){ 
                            dir.mkdirs(); 
                        } 
                        File file=new File(path+"/"+dir1+"/"+dir2+newFileName); 
                        fi.write(file); 
                    } 
                } 
            } catch (FileUploadException e) { 
                e.printStackTrace(); 
            } catch (Exception e) { 
                e.printStackTrace(); 
            } finally { 
                if (fi==null){ 
                    fi.delete();//清临时文件 
                } 
            } 
        } 
    } 

这里的文件上传使用到了apache的两个公共包,commons-fileupload-1.2.2.jar和commons-io-2.1.jar

将这两个包导到项目的WEB-INF下的lib目录下即可。


关于文件上传:

1、文中使用ServletFileUpload类新建了一个upload对象,这个对象还有两个方法没有出现在文中,但是也是经常使用的,setFileSizeMax(long fileSizeMax)设置所有上传文件大小之和的最大值和setSizeMax(long sizeMax)设置每个文件最大值。如下:

upload.setFileSizeMax(1024*1024*Cool;//设置每个文件最大为8M
upload.setSizeMax(1024*1024*20);//所有上传文件大小之和的最大值为20M

2、request.setCharacterEncoding("utf-8");这句解决上传文件名的中文乱码
注意,上面这句设置中文,如果是“multipart/form-data”表单,可以设置其中file组件的文件名,但对其中的普通表单组件无效。
注意,上面这句设置中文,如果是我们以前用的“application/x-www-form-urlencoded”表单,可以设置其中的普通表单组件。
3、代码中最后将fi写到指定目录时,还可以使用如下方法:

程序代码:
FileUtils.copyInputStreamToFile(fi.getInputStream(), file); 

//真正的文件内容其实在 fi.getInputStream() 当中

关于打散目录:

对于每一个字符串,他都有一个hash值与之对应,这里就是用他的最后四位与最后四位全为16(十六进制的 f ),其他全为0的十六进制数进行与运算得出来的十六进制数转换成字符串作为一级目录;用他的后五到八位全为16(十六进制的 f ),其他全为0的十六进制数进行与运算得出来的十六进制数全部右移四位再转换成字符串作为二级目录。


关于进度条:

这里我们只是做了一个最简单的进度条的演示,而且还不能做成平时电脑上操作时的那种进度条,我这里只是将其输出到网页上而已,效果如下:


这种看上去会让人失望,但的确是有在监控的,因为这里没有使用ajax技术,无法做到点对点的监控,等后面我会使用ajax技术重新做一个的。

这里其实就是使用了ServletFileUpload类中的一个函数setProgressListener(),早代码中已经体现出来了。

最后就是关于抓异常最后的finally中清缓冲区中的临时文件的,在那里清除的意义在于防黑,假如有人上传一半就中断了,那么就会跳到finally那里去,这个时候就应该清除缓存了。
已记录


原生态特色礼品:沉香 紫檀 黄花梨
页: [1] 向上 打印 
原生态论坛  |  设计专版  |  网页/程序设计 (版主: tianya)  |  主题: java---文件上传/打散目录/进度条 « 上一篇主题 下一篇主题 »
跳到:  

友情链接: 原生态购物网 原生态官方博客  佛珠网  搜狐社区 淑女情缘论坛 沉香
  原生态论坛© 2005~2017, www.sinobuy.cn 版权所有
Powered by SMF 1.1 RC1 Lewis Media.
Powered by MySQL  Powered by PHP  Valid XHTML 1.0!  Valid CSS!