Cheug's Blog

当前位置:网站首页 / JAVA / 正文

文件上传和下载

2019-08-09 / JAVA / 922 次围观 / 0 次吐槽 /

文件上传的原理分析

  文件上传的前提

Ø 提供form表单,method必须是post

Ø form表单的enctype必须是multipart/form-data

Ø 提供input type="file"类的上传输入域

enctype属性

enctype作用:告知服务器请求正文的MIME类型。(请求消息头:Content-Type作用是一致的)

可选值:

application/x-www-form-urlencoded(默认)

正文:username=admin&password=123

服务器获取数据:String username = request.getParameter("username");

multipart/form-data:

正文:使用IE的开发人员工具来测试

服务器获取数据:request.getParameter(String)方法获取指定的表单字段字符内容,但文件上传表单已经不在是字符内容,而是字节内容,所以失效

image.png

文件上传案例

upload.jsp

<html>
  <head>
    <title>文件上传</title>
  </head>
  <body>
    <form action="${pageContext.request.contextPath}/UploadServlet" method="post" enctype="multipart/form-data">
        用户名:<input type="text" name="username"><br/>
        密  码:<input type="password" name="password"><br/>
        上  传:<input type="file" name="file"><br/>
        <input type="submit" value="提交">
    </form>
  </body>
</html>

UploadServlet

//获取输入流
InputStream inputStream = request.getInputStream();

//读取
int len = 0;
byte[] bytes = new byte[1024 * 8];
while((len = inputStream.read(bytes)) != -1){
    String str = new String(bytes,0,len,"UTF-8");
    System.out.println(str);
}

借用第三方解析文件

fileupload概述

Ø fileupload是由apachecommons组件提供的上传组件。它最主要的工作就是帮我们解析request.getInputStream()

 

Ø 使用fileupload只需要2jar

                commons-fileupload-1.2.2.jar

                commons-io-2.2.jar 

fileupload的核心类有:

DiskFileItemFactoryServletFileUploadFileItem

解析原理

image.png

FileItem对象介绍

Ø FileItem对象对应一个表单项(表单字段)。可以是文件字段或普通字段

Ø boolean isFormField():判断当前表单字段是否为普通文本字段,如果返回false,说明是文件字段;

Ø String getFieldName():获取字段名称,例如:<input type=textname=username/>,返回的是username

Ø String getString():获取字段的内容,如果是文件字段,那么获取的是文件内容,当然上传的文件必须是文本文件;

Ø String getName():获取文件字段的文件名称;(a.txt

Ø String getContentType():获取上传的文件的MIME类型,例如:text/plain

Ø int getSize():获取上传文件的大小;

Ø InputStream getInputStream():获取上传文件对应的输入流;

Ø void write(File):把上传的文件保存到指定文件中。

Ø delete():删除临时文件

使用fileupload实现文件上传代码

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //获取表单文件数据
    DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();//创建工厂对象
    ServletFileUpload upload = new ServletFileUpload(diskFileItemFactory);//创建文件上传对象

    try {
        List<FileItem> items = upload.parseRequest(request);//获取FileItem/标签数据
        for (FileItem item : items){
            if(item.isFormField()){//普通数据
                System.out.println(item.getFieldName() + "--" + item.getString("UTF-8"));
            }else{//文件数据
                //取当前日期
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                String date = simpleDateFormat.format(new Date());
                String path = request.getServletContext().getRealPath("upload\\" + date);//保存路径
                //创建文件夹
                File dir = new File(path);
                if (!dir.exists()){//不存在
                    dir.mkdirs();
                }
                //保存
                String suffix = item.getName().split("\\.")[item.getName().split("\\.").length - 1];//后缀
                String name = UUID.randomUUID().toString() + "." + suffix;//文件名
                String dirPath = path + "\\" + name;
                try {
                    item.write(new File(dirPath));
                    item.delete();//删除临时文件
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    } catch (FileUploadException e) {
        e.printStackTrace();
    }
}

文件上传保存路径的几种方案

方案一:添加日期目录,方便分类查找

image.png

方式二:把日期20180108转成16进制字符串d12fde2f

image.png

文件上传应该注意的问题

中文乱码问题

表单普通字段乱码用item.getString("UTF-8");

文件名乱码可用

image.png

文件上传大小限制问题

单个文件大小:

ServletFileUpload.setFileSizeMax(字节)

image.png

总文件大小:(多文件上传)

ServletFileUpload.setSizeMax(字节)

临时文件的问题

Ø DiskFileItemFactory:

作用:产生FileItem对象

内部有一个缓存,缓存大小默认是10Kb。如果上传的文件超过10Kb,用磁盘作为缓存。

存放缓存文件的目录在哪里?默认是系统的临时目录。

如果自己用IO流实现的文件上传,要在流关闭后,清理临时文件。调用FileItem.delete();

 

多文件上传

image.png

文件下载

文件下载需要设置响应头

Content-Disposition

attachment;filename=xx.png

以附件形式下载

Content-Type

application/octet-stream

二进制流

案例下载代码

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //获取文件信息
    String fileName = request.getParameter("file");
    String fileDate = request.getParameter("date");
    //组合文件路径
    String filePath = request.getServletContext().getRealPath("upload\\" + fileDate) + "\\" + fileName;
    //发送文件
    File file = new File(filePath);
    if(file.exists()){
        //设置请求头
        fileName = URLEncoder.encode(fileName,"UTF-8");//文件名设置UTF-8编码
        response.setHeader("Content-disposition","attachment;filename=" + fileName);
        response.setContentType("application/octet-stream");//以二进制的数据返回客户端

        FileInputStream fileInputStream = new FileInputStream(file);
        byte[] buf = new byte[1024 * 8];//缓冲区
        ServletOutputStream outputStream = response.getOutputStream();
        int len = 0;
        while((len = fileInputStream.read(buf)) != -1){
            outputStream.write(buf,0,len);
        }
        fileInputStream.close();
        outputStream.close();
    }else{
        response.setHeader("content-type","text/html;charset=UTF-8");
        response.getWriter().write("文件不存在");
    }


}


Powered By Cheug's Blog

Copyright Cheug Rights Reserved.