文件上传功能应用非常广泛,例如:头像上传、商品图片、新闻图片、相册、网盘
文件上传
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)
);
day20 文件上传与下载
最新推荐文章于 2020-02-12 20:18:51 发布