目录
-
文件上传
- 文件上传:将本地的文件通过流写入到服务器的过程。
-
文件上传的技术
- JSPSmartUpload :应用在JSP上的文件上传和下载的组件。
- FileUpload :应用在Java环境上的文件上传的功能。
- Servlet3.0 :提供文件上传的功能
- Struts2 :提供文件上传的功能
-
文件上传的要素
- 文件上传的三个要素
- 表单的提交的方式需要是POST
- 表单中需要有<input type=”file”>元素,需要有name属性和值。
- 表单enctype=”multipart/form-data”
-
文件上传的原理
- 抓包分析
- 没有设置enctype属性
POST /web06/jsp/upload.jsp HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
X-HttpWatch-RID: 22006-10011
Referer: http://localhost:8080/web06/jsp/upload.jsp
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: localhost:8080
Content-Length: 53
DNT: 1
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: JSESSIONID=D51DCB996556C94861B2C72C4D978010
info=info&upload=C%3A%5CUsers%5Cjt%5CDesktop%5Caa.txt
注意:没有文件上传中的文件的具体的内容。
- 设置enctype属性
POST /web06/jsp/upload.jsp HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
X-HttpWatch-RID: 22006-10026
Referer: http://localhost:8080/web06/jsp/upload.jsp
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Content-Type: multipart/form-data; boundary=---------------------------7e139d10110a64
Accept-Encoding: gzip, deflate
Host: localhost:8080
Content-Length: 322
DNT: 1
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: JSESSIONID=D51DCB996556C94861B2C72C4D978010
-----------------------------7e139d10110a64
Content-Disposition: form-data; name="info"
aaa
-----------------------------7e139d10110a64
Content-Disposition: form-data; name="upload"; filename="C:\Users\jt\Desktop\aa.txt"
Content-Type: text/plain
hello world!!!
-----------------------------7e139d10110a64--
-
文件上传的入门案例
- 第一步:引入文件上传的相关的jar包。
- 上传的页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>文件上传</h3>
<!-- 文件上传三要素
* 表单需要是post提交
* 表单中需要文件上传项,必须有name的属性和值
* 表单的enctype属性必须是multipart/form-data
-->
<form action="${ pageContext.request.contextPath }/UploadFile" method="post" enctype="multipart/form-data">
文件描述:<input type="text" name="info" width="128" height="128"><br/>
上传文件:<input type="file" name="upload"><br/>
<input type="submit" value="上传"/>
</form>
</body>
</html>
上传代码
package com.toroidals.uploadfile;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
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;
/**
* 上传文件
*/
public class UploadFile extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
// 1.创建磁盘文件项工厂
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
// 2.创建一个核心的解析类
ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);
// 3.利用核心类解析Request,解析后会得到多个部分。返回一个List集合。List集合装的是每个部分的内容(FileItem文件项)。
List<FileItem> list = fileUpload.parseRequest(request);
// 4.遍历List集合,会得到代表每个部分的文件项的对象。根据文件项判断是否是文件上传项。
for (FileItem fileItem : list) {
// 判断这个文件项是否是普通项还是文件上传项。
if (fileItem.isFormField()) {
// 普通项:
// 接收普通项的值:(接收值不能再使用request.getParameter())
String name = fileItem.getFieldName();// 获得普通项的名称
// 获得普通项的值
String value = fileItem.getString("UTF-8");
System.out.println(name + " " + value);
} else {
// 文件上传项:
// 获得文件上传项的文件的名称:
String filename = new File(fileItem.getName()).getName();
//获得上传文件的输入流
InputStream inputStream = fileItem.getInputStream();
//获得服务器的绝对路径
String realPath = this.getServletContext().getRealPath("/file");
String filePath = realPath + "\\" + filename;
System.out.println(filePath);
//创建一个输出流,写入到指定路径
OutputStream outputStream = new FileOutputStream(filePath);
//传输数据
int len;
byte[] bytes = new byte[8192];
while((len = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, len);
}
inputStream.close();
outputStream.close();
System.out.println("文件上传成功");
}
}
} catch (FileUploadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
-
文件上传的API
-
DiskFileItemFactory:磁盘文件项工厂
- 构造方法:
-
- DiskFileItemFactory()
- DiskFileItemFactory(int sizeThreshold,File repostory)
- sizeThreshold :设置文件上传的缓冲区的大小,默认值为10kb。
- repository :设置文件上传过程中产生临时文件存放的路径。
方法:
void | setRepository(java.io.File repository) 设置用于临时存储大于配置大小阈值的文件的目录。 |
void | setSizeThreshold(int sizeThreshold) 设置直接写入磁盘的临时文件的大小阈值。 |
- setSizeThreshold() :设置缓冲区的大小
- setRepository() :设置临时文件存放的路径
- API的使用的代码
package com.toroidals.uploadfile;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
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;
/**
* 上传文件
*/
public class UploadFile extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
// 1.创建磁盘文件项工厂
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
// 1.1设置缓冲区的大小:
diskFileItemFactory.setSizeThreshold(5 * 1024 * 1024); //设置缓冲区的大小为5M
// 1.2设置临时文件存放的路径:
// 获得临时文件存放的路径:
String tempFilePath = this.getServletContext().getRealPath("/temp");
System.out.println("tempFilePath" + tempFilePath);
diskFileItemFactory.setRepository(new File(tempFilePath));
// 2.创建一个核心的解析类
ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);
// 3.利用核心类解析Request,解析后会得到多个部分。返回一个List集合。List集合装的是每个部分的内容(FileItem文件项)。
List<FileItem> list = fileUpload.parseRequest(request);
// 4.遍历List集合,会得到代表每个部分的文件项的对象。根据文件项判断是否是文件上传项。
for (FileItem fileItem : list) {
// 判断这个文件项是否是普通项还是文件上传项。
if (fileItem.isFormField()) {
// 普通项:
// 接收普通项的值:(接收值不能再使用request.getParameter())
String name = fileItem.getFieldName();// 获得普通项的名称
// 获得普通项的值
String value = fileItem.getString("UTF-8");
System.out.println(name + " " + value);
} else {
// 文件上传项:
// 获得文件上传项的文件的名称:
String filename = new File(fileItem.getName()).getName();
//获得上传文件的输入流
InputStream inputStream = fileItem.getInputStream();
//获得服务器的绝对路径
String realPath = this.getServletContext().getRealPath("/file");
String filePath = realPath + "\\" + filename;
System.out.println(filePath);
//创建一个输出流,写入到指定路径
OutputStream outputStream = new FileOutputStream(filePath);
//传输数据
int len;
byte[] bytes = new byte[8192];
while((len = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, len);
}
inputStream.close();
outputStream.close();
System.out.println("文件上传成功");
}
}
} catch (FileUploadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
临时文件和目标文件一样大
-
ServletFileUpload:核心解析类
ServletFileUpload:核心解析
- 是用来判断表单的enctype属性是否正确
- 解析Request对象,返回一个List集合(每个部分的对象FileItem)
- 设置单个文件的大小
- 设置上传的文件的总大小
- 设置中文文件名上传的乱码的问题
设置监听文件上传的进度
去掉 uploadFile form表单的属性 enctype="multipart/form-data" 之后
限制上传你文件大小
-
FileItem文件
- 判断表单项是普通项还是文件上传项。如果为true代表是普通项
普通项的方法:
1.获得普通的名称
1.获得普通项的值
文件上传项:
获得文件上传的文件名
获得文件上传的文件内容
获得文件上传的文件的大小
删除文件上传过程中的临时文件
当上传文件的大小超过缓冲区大小就会生成临时文件,上传完成之后调用delete()方法可删除临时文件
fileItem.delete();
package com.toroidals.uploadfile;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
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;
/**
* 上传文件
*/
public class UploadFile extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
// 判断表单的enctype属性:
boolean flag = ServletFileUpload.isMultipartContent(request);
if(!flag){
// enctype属性不是 multipart/form-data
request.setAttribute("msg", "表单的格式不正确!");
request.getRequestDispatcher("/upload/uploadFile.jsp").forward(request, response);
return;
}
// 1.创建磁盘文件项工厂
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
// 1.1设置缓冲区的大小:
diskFileItemFactory.setSizeThreshold(5 * 1024 * 1024); //设置缓冲区的大小为5M
// 1.2设置临时文件存放的路径:
// 获得临时文件存放的路径:
String tempFilePath = this.getServletContext().getRealPath("/temp");
System.out.println("tempFilePath" + tempFilePath);
diskFileItemFactory.setRepository(new File(tempFilePath));
// 2.创建一个核心的解析类
ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);
// 设置文件上传的文件的最大大小
//fileUpload.setSizeMax(10*1024*1024);
// 3.利用核心类解析Request,解析后会得到多个部分。返回一个List集合。List集合装的是每个部分的内容(FileItem文件项)。
List<FileItem> list = fileUpload.parseRequest(request);
// 4.遍历List集合,会得到代表每个部分的文件项的对象。根据文件项判断是否是文件上传项。
for (FileItem fileItem : list) {
// 判断这个文件项是否是普通项还是文件上传项。
if (fileItem.isFormField()) {
// 普通项:
// 接收普通项的值:(接收值不能再使用request.getParameter())
String name = fileItem.getFieldName();// 获得普通项的名称
// 获得普通项的值
String value = fileItem.getString("UTF-8");
System.out.println(name + " " + value);
} else {
// 文件上传项:
// 获得文件上传项的文件的名称:
String filename = new File(fileItem.getName()).getName();
//获得上传文件的输入流
InputStream inputStream = fileItem.getInputStream();
//获得服务器的绝对路径
String realPath = this.getServletContext().getRealPath("/file");
String filePath = realPath + "\\" + filename;
System.out.println(filePath);
//创建一个输出流,写入到指定路径
OutputStream outputStream = new FileOutputStream(filePath);
//传输数据
int len;
byte[] bytes = new byte[8192];
while((len = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, len);
}
inputStream.close();
outputStream.close();
// 删除临时文件
fileItem.delete();
System.out.println("文件上传成功");
}
}
} catch (FileUploadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
自动删除临时文件
-
JS控制多文件上传
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
function add(){
// 获得id为div1的元素:
var div01Element = document.getElementById("div01");
div01Element.innerHTML += "<div><input type='file' name='upload'/><input type='button' value='删除' onclick='del(this)'></div>";
}
function del(who){
/* var divv = who.parentNode;
divv.parentNode.removeChild(divv); */
who.parentNode.parentNode.removeChild(who.parentNode);
}
</script>
</head>
<body>
<h1> ${ msg }</h1>
<h1>多文件上传</h1>
<form action="${ pageContext.request.contextPath }/UploadFile" method="post" enctype="multipart/form-data">
<input type="button" value="添加" onclick="add()"/>
<input type="submit" value="上传" /><br>
<div id="div01">
<div><input type="file" name="upload"/><input type="button" value="删除" onclick="del(this)"></div>
</div>
</form>
</body>
</html>
package com.toroidals.uploadfile;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
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;
/**
* 上传文件
*/
public class UploadFile extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
// 判断表单的enctype属性:
boolean flag = ServletFileUpload.isMultipartContent(request);
if(!flag){
// enctype属性不是 multipart/form-data
request.setAttribute("msg", "表单的格式不正确!");
request.getRequestDispatcher("/upload/uploadFile.jsp").forward(request, response);
return;
}
// 1.创建磁盘文件项工厂
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
// 1.1设置缓冲区的大小:
diskFileItemFactory.setSizeThreshold(5 * 1024 * 1024); //设置缓冲区的大小为5M
// 1.2设置临时文件存放的路径:
// 获得临时文件存放的路径:
String tempFilePath = this.getServletContext().getRealPath("/temp");
System.out.println("tempFilePath" + tempFilePath);
diskFileItemFactory.setRepository(new File(tempFilePath));
// 2.创建一个核心的解析类
ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);
// 设置文件上传的文件的最大大小
//fileUpload.setSizeMax(10*1024*1024);
// 3.利用核心类解析Request,解析后会得到多个部分。返回一个List集合。List集合装的是每个部分的内容(FileItem文件项)。
List<FileItem> list = fileUpload.parseRequest(request);
// 4.遍历List集合,会得到代表每个部分的文件项的对象。根据文件项判断是否是文件上传项。
for (FileItem fileItem : list) {
// 判断这个文件项是否是普通项还是文件上传项。
if (fileItem.isFormField()) {
// 普通项:
// 接收普通项的值:(接收值不能再使用request.getParameter())
String name = fileItem.getFieldName();// 获得普通项的名称
// 获得普通项的值
String value = fileItem.getString("UTF-8");
System.out.println(name + " " + value);
} else {
// 文件上传项:
// 获得文件上传项的文件的名称:
String filename = new File(fileItem.getName()).getName();
//获得上传文件的输入流
InputStream inputStream = fileItem.getInputStream();
//获得服务器的绝对路径
String realPath = this.getServletContext().getRealPath("/file");
String filePath = realPath + "\\" + filename;
System.out.println(filePath);
//创建一个输出流,写入到指定路径
OutputStream outputStream = new FileOutputStream(filePath);
//传输数据
int len;
byte[] bytes = new byte[8192];
while((len = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, len);
}
inputStream.close();
outputStream.close();
// 删除临时文件
fileItem.delete();
System.out.println("文件上传成功");
}
}
} catch (FileUploadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
-
文件上传兼容浏览器问题
如果使用IE老版本的浏览器出现一个文件名称获取错误问题。IE老版本获取文件名称的时候,会带有路径。
- 问题解决
- 利用File类的实例方法 getName() 从路径中获取文件名
// 获得文件上传项的文件的名称:
String filename = new File(fileItem.getName()).getName();
2.判断是否包含\
int idx = filename.lastIndexOf("\\");
if(idx != -1){
// 使用老版本浏览器:
filename = filename.substring(idx+1);
}
-
文件上传同一个目录下文件同名问题
张三向服务器上传了一个文件aa.txt内容是hello world。李四向服务器上传了一个文件aa.txt内容hello Java。后上传的文件将先上传的文件覆盖了。
- 解决方案
使用唯一文件名进行解决。
package com.toroidals.utils;
import java.util.UUID;
public class UploadUtils {
/**
* 传递一个文件名,返回一个唯一的文件名。
*/
public static String getUniqueName(String fileName) {
// 在Java的API中有一个类UUID可以产生随机的字符串。aa.txt
// UUID.randomUUID().toString();
// 获得文件名的扩展名.
int idx = fileName.lastIndexOf(".");
String extetions = fileName.substring(idx);
return UUID.randomUUID().toString().replace("-", "")+extetions;
}
/**
* 目录分离的算法实现
* @param args
*/
public static String getDir(String filename, int tierNum) {
int fileCode = filename.hashCode();
String path = "";
for (int i = 0; i < tierNum; i++) {
path += "\\" + (fileCode & 0xf);
fileCode = fileCode >>> 4;
}
return path;
}
public static String getDir(String filename) {
int fileCode = filename.hashCode();
String path = "";
for (int i = 0; i < 2; i++) {
path += "\\" + (fileCode & 0xf);
fileCode = fileCode >>> 4;
}
return path;
}
}
-
文件上传同一个目录下文件过多的问题
现在所有的用户都上传文件,如果网站访问量比较大,如果都上传到同一个目录下,在同一个目录下存放的文件太多了,也会对程序有影响(其实打开该目录的时候,都会很卡,更别说读写操作)
- 解决方案
- 目录分离
- 按时间分离 :按月、周、天、小时。
- 按用户分离 :按张三、李四。
- 按个数分离 :一个目录下存放3000个文件。
- 按目录分离算法 :按照某种特定算法进行分离。
- 上传一个文件,得到一个唯一的文件名。
- 唯一文件名获取其hashCode值。-----int类型的值(32位)
- 让hashCode的值 & 0xf;-----得出的这个值作为一级目录。
- 让hashCode右移4位 & 0xf;----得出的这个值作为二级目录。
- 以此类推。
- 分析算法:
String filename = UploadUtils.getUniqueName(new File(fileItem.getName()).getName());
//获得上传文件的输入流
InputStream inputStream = fileItem.getInputStream();
//获得服务器的绝对路径
String realPath = this.getServletContext().getRealPath("/file");
//根据文件名按按目录分离算法获得目录(2表示2级目录)
String fullDir = realPath + UploadUtils.getDir(filename, 2);
//创建目录
File filedir = new File(fullDir);
if(!filedir.isDirectory()) {
filedir.mkdirs();
}
String fullPath = fullDir + "\\" + filename;
System.out.println(fullPath);
package com.toroidals.uploadfile;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
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 com.toroidals.utils.UploadUtils;
/**
* 上传文件
*/
public class UploadFile extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
// 判断表单的enctype属性:
boolean flag = ServletFileUpload.isMultipartContent(request);
if(!flag){
// enctype属性不是 multipart/form-data
request.setAttribute("msg", "表单的格式不正确!");
request.getRequestDispatcher("/upload/uploadFile.jsp").forward(request, response);
return;
}
// 1.创建磁盘文件项工厂
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
// 1.1设置缓冲区的大小:
diskFileItemFactory.setSizeThreshold(5 * 1024 * 1024); //设置缓冲区的大小为5M
// 1.2设置临时文件存放的路径:
// 获得临时文件存放的路径:
String tempFilePath = this.getServletContext().getRealPath("/temp");
System.out.println("tempFilePath" + tempFilePath);
diskFileItemFactory.setRepository(new File(tempFilePath));
// 2.创建一个核心的解析类
ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);
// 设置文件上传的文件的最大大小
//fileUpload.setSizeMax(10*1024*1024);
// 3.利用核心类解析Request,解析后会得到多个部分。返回一个List集合。List集合装的是每个部分的内容(FileItem文件项)。
List<FileItem> list = fileUpload.parseRequest(request);
// 4.遍历List集合,会得到代表每个部分的文件项的对象。根据文件项判断是否是文件上传项。
for (FileItem fileItem : list) {
// 判断这个文件项是否是普通项还是文件上传项。
if (fileItem.isFormField()) {
// 普通项:
// 接收普通项的值:(接收值不能再使用request.getParameter())
String name = fileItem.getFieldName();// 获得普通项的名称
// 获得普通项的值
String value = fileItem.getString("UTF-8");
System.out.println(name + " " + value);
} else {
// 文件上传项:
// 获得文件上传项的文件的名称:
String filename = UploadUtils.getUniqueName(new File(fileItem.getName()).getName());
//获得上传文件的输入流
InputStream inputStream = fileItem.getInputStream();
//获得服务器的绝对路径
String realPath = this.getServletContext().getRealPath("/file");
//根据文件名按按目录分离算法获得目录(2表示2级目录)
String fullDir = realPath + UploadUtils.getDir(filename, 2);
//创建目录
File filedir = new File(fullDir);
if(!filedir.isDirectory()) {
filedir.mkdirs();
}
String fullPath = fullDir + "\\" + filename;
System.out.println(fullPath);
//创建一个输出流,写入到指定路径
OutputStream outputStream = new FileOutputStream(fullPath);
//传输数据
int len;
byte[] bytes = new byte[8192];
while((len = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, len);
}
inputStream.close();
outputStream.close();
// 删除临时文件
fileItem.delete();
System.out.println("文件上传成功");
}
}
} catch (FileUploadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
tempFilePathE:\JAVA2\temp
E:\JAVA2\file\2\1\e0b19dc1c80b40a38a6056bce6969ca4.chm
文件上传成功
E:\JAVA2\file\3\7\aabdba5391b2469f919e7650a48184c8.txt
文件上传成功
E:\JAVA2\file\15\4\52c13bf2cdee49aeb57dfe06c4eed57a.java
文件上传成功
E:\JAVA2\file\14\2\0b2b6ce872a240f1840286af7b5c01c4.jar
文件上传成功
E:\JAVA2\file\0\10\3383c088886f4805a988720c7768c6de.mp4
文件上传成功
-
文件下载
- 文件下载:将服务器上的一个文件,通过流写入到客户端上。
-
文件下载的方式
- 使用超链接的方式实现文件的下载
- 在<a href=”文件的路径”>超链接</a>
- 注意:超链接的方式,如果浏览器不能识别这种格式的文件,提示下载,如果支持该格式的文件,直接打开。
- 通过手动编写代码的方式实现文件的下载
- 设置两个头和一个流
- Content-Type :文件的MIME的类型
- Content-Disposition :浏览器支持该格式的文件,提示下载
- 设置代表该文件的输入流(输出流是固定 response.getOutputStream())
- 设置两个头和一个流
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>
<h3><a href="${ pageContext.request.contextPath }/download/1.jpg">1.jpg</a></h3>
<h3><a href="${ pageContext.request.contextPath }/download/aa.zip">aa.zip</a></h3>
<h1>文件下载:手动编码的方式</h1>
<h3><a href="${ pageContext.request.contextPath }/DownloadServlet?filename=1.jpg">1.jpg</a></h3>
<h3><a href="${ pageContext.request.contextPath }/DownloadServlet?filename=aa.zip">aa.zip</a></h3>
</body>
</html>
package com.toroidals.download;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 文件下载的Servlet
*/
public class DownloadServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.接收参数:
String filename = request.getParameter("filename");
// 2.下载:设置两个头和一个流
// 设置Content-Type
String type = getServletContext().getMimeType(filename);
response.setContentType(type);
// 定义一个代表该文件的路径:
String path = getServletContext().getRealPath("/download");
File file = new File(path+"/"+filename);
// 设置Content-Disposition
response.setHeader("Content-Disposition", "attachment;filename="+filename);
// 设置一个代表了文件的输入流
InputStream is = new FileInputStream(file);
OutputStream os = response.getOutputStream();
// 两个流对接:
int len;
byte[] bytes = new byte[8192];
while((len = is.read(bytes))!=-1){
os.write(bytes, 0, len);
}
is.close();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doGet(request, response);
}
}
-
中文文件的下载
- 中文文件的下载:(出现乱码问题)
- 不同的浏览器对中文文件的下载的编码不一样的。
- IE浏览器采用的是URL编码
- Firefox浏览器采用的是Base64编码
- 判断客户端使用的浏览器的类型
- User-Agent请求头可以获得客户端浏览器信息。
- 不同的浏览器对中文文件的下载的编码不一样的。
package com.toroidals.download;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.toroidals.download.DownloadUtils;
/**
* 文件下载的Servlet
*/
public class DownloadServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.接收参数:
String filename = new String(request.getParameter("filename").getBytes("ISO-8859-1"),"UTF-8");
System.out.println("filename" + filename);
// 2.下载:设置两个头和一个流
// 设置Content-Type
String type = getServletContext().getMimeType(filename);
response.setContentType(type);
// 定义一个代表该文件的路径:
String path = getServletContext().getRealPath("/download");
File file = new File(path+"/"+filename);
// 判断浏览器的类型:
String agent = request.getHeader("User-Agent");
if(agent.contains("Firefox")){
// 使用的是Firefox
filename = DownloadUtils.base64EncodeFileName(filename);
}else{
// IE或者其他的浏览器
filename = URLEncoder.encode(filename, "UTF-8");
}
// 设置Content-Disposition
response.setHeader("Content-Disposition", "attachment;filename="+filename);
// 设置一个代表了文件的输入流
InputStream is = new FileInputStream(file);
OutputStream os = response.getOutputStream();
// 两个流对接:
int len = 0;
byte[] b = new byte[1024];
while((len = is.read(b))!=-1){
os.write(b, 0, len);
}
is.close();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doGet(request, response);
}
}
-
给定目录下的文件下载
- 需求描述
给定一个目录(这个目录可以是任意盘符下的任意路径—这个路径下有多少级目录,每级目录中有多少个文件都是未知的)。将这个路径中的文件显示到页面上,在页面上给每个问题件都提供响应下载的链接,当点击这个链接的时候,对该文件进行下载。
广度优先遍历:先将根节点入队,再从队列中取出一个节点,将该节点下所有非叶子节点入队,叶子结点取出另存;再从队列中取出一个节点,将该节点下所有非叶子节点入队,叶子结点取出另存...
深度优先遍历:采用递归的方式
注意:以为此次传的是绝对路径,get请求传参时参数中包含特殊字符“/”,所以在传参之前先解码,在后台接收参数时先编码
<h4><a href="${ pageContext.request.contextPath }/DownloadListServlet?filename=<%=URLEncoder.encode(f.getCanonicalPath(), "UTF-8")%>"> <%= f.getName() %></a></h4>
// 接收参数:
String path = URLDecoder.decode(request.getParameter("filename"), "UTF-8");
<%@page import="java.io.File"%>
<%@page import="java.net.URLEncoder"%>
<%@page import="java.util.*"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>
<%
// 1.创建一个队列:
Queue<File> queue = new LinkedList<File>();
// 2.先将跟节点入队:
File root = new File("E:\\work_space\\javaEclipse\\UploadDownload\\WebContent\\downloadList");
queue.offer(root);
// 判断这个队列是否为空,不为空需要进行遍历:
while(!queue.isEmpty()){
// 将跟节点出队:
File file = queue.poll();
// 获得跟节点下的所有子节点:
File[] files = file.listFiles();
// 遍历所有子节点:
for(File f:files){
// 判断该节点是否为叶子节点:
if(f.isFile()){
%>
<h4><a href="${ pageContext.request.contextPath }/DownloadListServlet?filename=<%=URLEncoder.encode(f.getCanonicalPath(), "UTF-8")%>"> <%= f.getName() %></a></h4>
<%
}else{
queue.offer(f);
}
}
}
%>
</body>
</html>
package com.toroidals.download;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 树形的文件下载的代码实现
*/
public class DownloadListServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 接收参数:
String path = URLDecoder.decode(request.getParameter("filename"), "UTF-8");
System.out.println(path);
File file = new File(path);
// 实现文件下载:设置两个头和一个流:
// 获得文件名
String filename = file.getName();
response.setContentType(getServletContext().getMimeType(filename));
// 设置另一个头:
String agent = request.getHeader("User-Agent");
if(agent.contains("Firefox")){
filename = DownloadUtils.base64EncodeFileName(filename);
}else{
filename = URLEncoder.encode(filename, "UTF-8");
filename = filename.replace("+", " ");
}
response.setHeader("Content-Disposition", "attachment;filename="+filename);
// 设置输入流:
InputStream is = new FileInputStream(file);
OutputStream os = response.getOutputStream();
int len = 0;
byte[] b = new byte[1024];
while((len = is.read(b))!=-1){
os.write(b, 0, len);
}
is.close();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doGet(request, response);
}
}