day20 文件上传与下载

文件上传功能应用非常广泛,例如:头像上传、商品图片、新闻图片、相册、网盘

文件上传
1、客户端,为用户提供文件上传输入框
2、服务器端,编写程序,将上传文件数据,保存到服务器端
* 将客户端一个文件,传递到服务器端

文件上传编程
1、编写上传文件form表单
提供input type="file" ,必须为上传项提供name属性,上传form表单必须post,enctype设置为multipart/form-data

2、服务器端,完全根据request.getInputStream 方法 对请求体内容进行分割,获得文件上传内容 ----- 非常麻烦
使用Apache 公司提供 commons-fileupload 工具包完成文件上传
* commons-fileupload  和  jsp smart upload 框架(在model1 时代主流使用) ----- 在Servlet3.0 之后,Servlet程序本身就支持文件上传

下载 commons-fileupload / commons-io 包 --- 将 jar包复制WEB-INF/lib
fileupload 快速入门
1、使用工厂 DiskFileItemFactory
2、通过工厂构造解析器 ServletFileupLoad
3、解析器将请求体各个部分 以分隔线切割 ---- 多个部分(每个部分就是FileItem)
4. 通过FileItem 的isFormField 判断是否为文件上传
上传文件
getInputStream 获得文件内容
getName 获得文件名

不是上传文件
getFieldName 获得name属性
getString 获得value属性

********** 对于老版本浏览器,会存在客户端路径,使用stringAPI 将路径切割掉

FileUpload 核心类 API详解
1、DiskFileItemFactory
setSizeThreshold(int sizeThreshold) ----- 设置内存缓冲区大小
setRepository(java.io.File repository ----- 设置临时文件存放位置

* 上传文件优先保存内存缓冲区,当内存缓存区不够用,在硬盘上产生临时文件,临时文件保存指定临时文件目录中
* 临时文件与源文件内容相同
* 中文附件名 乱码问题  ------------- upload.setHeaderEncoding("utf-8");
* 当上传文件完成时,删除临时文件 fileItem.delete();

2、ServletFileUpload
setHeaderEncoding(java.lang.String encoding) ----- 设置上传文件附件名编码(解决乱码)
parseRequest(HttpServletRequest request) ----- 解析请求体内容,返回List<FileItem>
isMultipartContent(javax.servlet.http.HttpServletRequest request) ----- 判断form的enctype是否为multipart/form-data (true 是文件上传form)
setFileSizeMax(long fileSizeMax) 设置单文件最大大小   setSizeMax(long sizeMax) 设置请求最大大小

***** setProgressListener(ProgressListener pListener) 为文件上传设置监听器,监听文件上传全过程
* 文件上传进度条

3、FileItem
isFormField() 是否为文件上传域,true不是文件上传,false是文件上传

如果不是文件上传
getFieldName  获得name属性
getString  获得value属性 ------------ 文件上传表单中request.setCharacterEncoding 不能使用,request.getParameter不能使用
* 请求中有中文 getString(java.lang.String encoding)

如果是文件上传
getName  获得文件名
getInputStream  获得文件内容

整理乱码解决:
附件名乱码 servletFileupload.setHeaderEncoding(编码)
普通form项中文乱码 fileItem.getString(编码)

文件上传注意问题
1、乱码问题(附件名乱码 servletFileupload.setHeaderEncoding,普通form项乱码fileItem.getString)
2、临时文件删除,必须先关闭FileItem的输入流,再调用FileItem.delete方法 删除临时文件
3、文件保存目录
* WEB-INF在浏览器端不允许通过URL直接访问
WEB-INF内 :必须通过服务器端程序去访问,Servlet ---- getRealPath(/WEB-INF) ---------------- 需要权限,需要身份认证
WEB-INF外 :浏览器直接通过URL访问  ------------------ 任何人都可以访问

思考:电影会员点播网站,在线看电影,收费。上传电影放到哪里? WEB-INF 里面
QQ头像、京东商城商品图片 。上传后 放到哪里? WEB-INF外面

4、将所有文件放到相同目录中,当文件重名时,会发生覆盖效果 -------- 上传文件名唯一
UUID + filename

5、当系统人气很高,当所有上传文件保存到一个目录时,随着系统使用,目录中文件数量非常巨大
* 目录出现访问非常慢,无法访问情况
* 采用目录分散算法
按时间(一天一目录)、按用户  ----- 最主流
每个目录存放固定数量文件  ----- 每个目录存放1000个文件。超过1000 新建一个目录
hachcode 存放分散目录

ProgressListener 文件上传进程监听器,监听文件上传进度 ------ 在页面上设计上传进度条 (AJAX案例)
传输速率 = 已经上传大小/已经使用时间;
剩余时间 = 剩余大小/速率;

1024 b/ms = (1024/1024)*1000 KB/S

--------------------------------------------------------------------------------------------------------------------------------------------
文件下载
第一种方式,用超链接指向要下载的文件 (DefaultServlet 将资源返回,如果浏览器对资源格式不识别,询问用户是否下载)
* 如果浏览器识别下载文件格式,自动打开,如果浏览器不识别文件格式,弹出下载框
* 因为直接通过url访问资源,资源存放WEB-INF目录之外,没有权限控制,直接下载

第二种方式,编写Servlet,在Servlet中获得要下载文件
* 在下载文件的程序中,必须设置两个响应头字段 Content-Type(MIME类型)、Content-Dispostion (以附件形式下载)
获得文件MIME类型 ----- tomcat/conf/web.xml 定义很多文件的MIME类型 -- ServletContext 提供getMimeType 根据文件扩展名获得文件MIME类型
* response.setContentType(getServletContext().getMimeType(file));
Content-Disposition : attachment;filename=xxx
* response.setHeader("Content-Dispostion", "attachment;filename=" + file);

案例:遍历服务器指定目录下所有文件,并提供下载
* 广度非递归 遍历
* 下载D:\TTPmusic 中所有音乐

getAbsolutePath ----- c:\aa\bb\..\1.txt ==== new File("c:\\aa\\bb","..\\1.txt");
getCanonicalPath ----- c:\aa\1.txt

两个问题:
1、浏览器在GET方式提交中文时,存在编码问题 ------- 解决:手动对提交中文进行编码
* URLEncoder 对get方式提交中文手动编码
2、在文件下载时,附件名存在乱码问题
* IE 对附件名编码 和 FF对附件名编码 不同
* IE 采用URL编码  URLEncoder.encode
* FF 采用BASE64编码  MimeUtility.encodeText

MimeUtility.encodeText 对中文内容进行Base64编码,但是如果编码内容中没有中文,该方法将什么也不做!
public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 使用get方式传递中文信息
        String path = request.getParameter("path");
        // get 乱码解决 --- 手动
        path = new String(path.getBytes("ISO-8859-1"), "utf-8");
        // 截取文件名
        String filename = path.substring(path.lastIndexOf("\\") + 1);

        // 设置两个头信息
        response.setContentType(getServletContext().getMimeType(filename));
        // 乱码问题 --- 不同浏览器解决方式不同
        String agent = request.getHeader("User-Agent");
        if (agent.contains("MSIE")) {
            // IE 浏览器 采用URL编码
            filename = URLEncoder.encode(filename, "utf-8");
            response.setHeader("Content-Disposition", "attachment;filename="
                    + filename);
        } else if (agent.contains("Mozilla")) {
            // 火狐浏览器 采用Base64编码
            // filename = MimeUtility.encodeText(filename);// 全英文不编码
            BASE64Encoder base64Encoder = new BASE64Encoder();
            filename = "=?UTF-8?B?"
                    + new String(base64Encoder.encode(filename
                            .getBytes("UTF-8"))) + "?=";

            response.setHeader("Content-Disposition", "attachment;filename="
                    + filename);
        } else {
            // 默认 不编码
            response.setHeader("Content-Disposition", "attachment;filename="
                    + filename);
        }

        InputStream in = new BufferedInputStream(new FileInputStream(path));
        OutputStream out = response.getOutputStream();
        int temp;
        while ((temp = in.read()) != -1) {
            out.write(temp);
        }

        in.close();
        out.close();
    }

JSP:
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@page import="java.util.LinkedList"%>
<%@page import="java.io.File"%>
<%@page import="java.net.URLEncoder"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>文件下载列表</h1>
<!-- 将D:\TTPmusic 中所有音乐文件,显示列表,允许用户下载 -->
<%
    // 遍历指定目录 --- 非递归广度
    File root = new File("F:\\12期完整");
    LinkedList<File> list = new LinkedList<File>();// 存储
    list.add(root);// 集合中存在一个目录
   
    while(!list.isEmpty()){
        // 集合不为空
        File currentDir = list.removeFirst();// 返回目录对象
        File[] files = currentDir.listFiles();// 获得目录下所有文件
        for(File f : files){
            if(f.isDirectory()){
                // 将未遍历目录 加入集合
                list.add(f);
            }else{
                // 是一个文件
                // get 、post 提交中文,使用URL编码   
//    <c:url value="/servlet/DownloadServlet" var="url">
//          <c:param name="filename" value="${me.key}"></c:param>
//      </c:url>
                String args = URLEncoder.encode(f.getCanonicalPath(),"utf-8");// 这个本来是浏览器默认动作,只是手动执行
                out.println("<a href='/day20/downloadMusic?path="+args+"'>"+f.getName()+"</a><br/>");
            }
        }
    }
%>
</body>
</html>
---------------------------------------------------------------------------------------------------------------------------------
编写文件上传下载系统(netdisk)
1、上传文件,任何都可以下载 ,练习文件下载程序,WEB-INF 里面
2、上传文件,hashcode目录分散算法
3、保证存放硬盘文件名 唯一 UUID
4、将上传文件基本信息 保存数据库里面

class Resource {
private int id;
private String uuidname;  //上传文件的名称,文件的uuid名
private String realname; //上传文件的真实名称
private String savepath;     //记住文件的位置
private Timestamp uploadtime;     //文件的上传时间
private String description;  //文件的描述
}

create table resource(
   id int primary key auto_increment,
   uuidname varchar(100),
   realname varchar(40),
   savepath varchar(40),
   uploadtime timestamp,
   description varchar(255)
);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值