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:
这里写图片描述

演示上传进度原理
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值