文件上传与下载
一、文件上传
1、jsp+Servlet(文件上传)开发步骤
实现web开发中的文件上传功能,需完成如下二步操作:
在web页面中添加上传输入项
在servlet中读取上传文件的数据,并保存到服务器硬盘中。
2、文件上传:如何在Servlet中读取文件上传数据,并保存到本地硬盘中?
Request对象提供了一个getInputStream方法,通过这个方法可以读取到客户端提交过来的数据。但由于用户可能会同时上传多个文件,在servlet端编程直接读取上传数据,并分别解析出相应的文件数据是一项非常麻烦的工作。
3、开源组件: Commons-fileupload
为方便用户处理文件上传数据,Apache 开源组织提供了一个用来处理表单文件上传的一个开源组件( Commons-fileupload ),该组件性能优异,并且其API使用极其简单,可以让开发人员轻松实现web文件上传功能,因此在web开发中实现文件上传功能,通常使用Commons-fileupload组件实现。
使用Commons-fileupload组件实现文件上传,需要导入该组件相应的支撑jar包:Commons-fileupload和commons-io。commons-io 不属于文件上传组件的开发jar文件,但Commons-fileupload 组件从1.1 版本开始,它工作时需要commons-io包的支持。
4、fileupload工作流程
5、文件上传实现步骤
1、创建DiskFileItemFactory对象,设置缓冲区大小和临时文件目录
2、使用DiskFileItemFactory 对象创建ServletFileUpload对象,并设置上传文件的大小限制。
3、调用ServletFileUpload.parseRequest方法解析request对象,得到一个保存了所有上传内容的List对象。
4、对list进行迭代,每迭代一个FileItem对象,调用其isFormField方法判断是否是上传文件
True 为普通表单字段,则调用getFieldName、getString方法得到字段名和字段值
False 为上传文件,则调用getInputStream方法得到数据输入流,从而读取上传数据。
6、上传核心api
(1)核心API—DiskFileItemFactory
DiskFileItemFactory是创建 FileItem 对象的工厂,这个工厂类常用方法:
publicDiskFileItemFactory(int sizeThreshold, java.io.File repository)
构造函数
public voidsetSizeThreshold(int sizeThreshold)
设置内存缓冲区的大小,默认值为10K。当上传文件大于缓冲区大小时, fileupload组件将使用临时文件缓存上传文件。
public voidsetRepository(java.io.File repository)
指定临时文件目录,默认值为System.getProperty("java.io.tmpdir").
(2)核心API—ServletFileUpload
ServletFileUpload 负责处理上传的文件数据,并将表单中每个输入项封装成一个 FileItem 对象中。
常用方法有:
booleanisMultipartContent(HttpServletRequest request)
判断上传表单是否为multipart/form-data类型
ListparseRequest(HttpServletRequest request)
解析request对象,并把表单中的每一个输入项包装成一个fileItem 对象,并返回一个保存了所有FileItem的list集合。
setFileSizeMax(long fileSizeMax)
设置单个上传文件的最大值
setSizeMax(long sizeMax)
设置上传文件总量的最大值
setHeaderEncoding(java.lang.String encoding)
设置编码格式,解决上传文件名乱码问题
setProgressListener(ProgressListener pListener)
实时监听文件上传状态
(3)核心API—FileItem
FileItem 用来表示文件上传表单中的一个上传文件对象或者普通表单对象
boolean isFormField() 判断FileItem是一个文件上传对象还是普通表单对象
如果判断是一个普通表单对象
String getFieldName() 获得普通表单对象的name属性
String getString(String encoding) 获得普通表单对象的value属性,可以用encoding进行编码设置
如果判断是一个文件上传对象
String getName() 获得上传文件的文件名(有些浏览器会携带客户端路径)
InputStreamgetInputStream() 获得上传文件的输入流
delete() 在关闭FileItem输入流后,删除临时文件
二、简单文件上传
1、文件上传表单
2、文件上传表单抓包情况
Stringname=request.getParameter("name");
Stringfile=request.getParameter("file");
System.out.println("name:"+name);//null 获取参数为空,说明此种获取上传文件的相关参数,获取失败
System.out.println("file:"+file);//null
因为是miei协议去描述传输参数,所以直接获取传输的表单参数获取失败
3、文件上传实现分析
通过浏览器去实现 文件的上传 .
第一个: 需要准备一个表单.
这个表单的 enctype属性的值必须是 multipart/form-data, 并且请求的方式需要是 post , 并且有个 input输入项的Type=”file”
第二个 :
需要去写一个服务器端程序来解析上传的数据, 将数据保存起来 ..
4、文件上传实现
(1)实现说明
【1】使用Commons-fileupload组件实现文件上传,需要导入该组件相应的支撑jar包:Commons-fileupload和commons-io
【2】一个表单页面:index.jsp和一个上传文件是否成功的返回信息页面message.jsp
【3】一个文件上传的servlet和配置文件web.xm
(2)index.jsp
<%@ page language="java" import="java.util.*"pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
<form action="${pageContext.request.contextPath}/upload" method="post"enctype="multipart/form-data" >
上传人:<input type="text"name="name"><br/>
上传文件:<input type="file" name="file"><br/>
<input type="submit"value="上传">
</form>
</body>
</html>
(3)message.jsp
<%@ page language="java" import="java.util.*"pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
${message}
</body>
</html>
(4)UploadServlet
package com.zhku.jsj144.zk.Servlet;
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;
/*
* 分析:
* Request对象提供了一个getInputStream方法,通过这个方法可以读取到客户端提交过来的数据。
* 但由于用户可能会同时上传多个文件,在servlet端编程直接读取上传数据,并分别解析出相应的文件数据是一项非常麻烦的工作.
*
* 使用:Commons-fileupload组件
* 为方便用户处理文件上传数据,Apache 开源组织提供了一个用来处理表单文件上传的一个开源组件( Commons-fileupload ),
* 该组件性能优异,并且其API使用极其简单,可以让开发人员轻松实现web文件上传功能,因此在web开发中实现文件上传功能,
* 通常使用Commons-fileupload组件实现。
*
* jar包:
* 使用Commons-fileupload组件实现文件上传,需要导入该组件相应的支撑jar包:Commons-fileupload和commons-io
*/
public class UploadServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String name=request.getParameter("name");
String file=request.getParameter("file");
System.out.println("name:"+name);//null 获取参数为空,说明此种获取上传文件的相关参数,获取失败
System.out.println("file:"+file);//null
/*
* 浏览器在上传文件时,将把文件数据附带在http请求消息体中,并使用MIME协议对上传的文件进行描述,
* 以方便接收方对上传数据进行解析和处理。
*/
try {
//1.创建工厂
DiskFileItemFactory factory=new DiskFileItemFactory();
//2.创建ServletFileUpload
ServletFileUpload parse=new ServletFileUpload(factory);
//3.获得解析器
List<FileItem> list = parse.parseRequest(request);
for (FileItem fileItem : list) {
//普通字段
if(fileItem.isFormField()){//是普通表单字段
String fieldName = fileItem.getFieldName();//字段名
// String name2 = fileItem.getName();
String value = fileItem.getString();//字段值
System.out.println("fieldName:"+fieldName);
// System.out.println("name2:"+name2);
System.out.println("value:"+value);
}
//文件
else{
String name3 = fileItem.getName();//文件名
System.out.println("name3:"+name3);
InputStream in = fileItem.getInputStream();//获取读取流
OutputStream out=new FileOutputStream("d:\\"+name3);
// OutputStream out=new FileOutputStream(new File("d:\\"+name3));
byte[] buf=new byte[1024];//缓冲区
int len=0;//读取字节长度
//读取的数据没有放到缓冲区中
// while((len=in.read())>0){
// while((len=in.read())!=-1){
while((len=in.read(buf))>0){
out.write(buf, 0, len);//将读取到的内容写到输出流中,保存在文件中
}
in.close();
out.close();
}
}
request.setAttribute("message", "上传文件成功");
request.getRequestDispatcher("/message.jsp").forward(request, response);
} catch (FileUploadException e) {
request.setAttribute("message", "上传文件失败");
request.getRequestDispatcher("/message.jsp").forward(request, response);
e.printStackTrace();
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
(5)web.xml
<?xml version="1.0"encoding="UTF-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>UploadServlet</servlet-name>
<servlet-class>com.zhku.jsj144.zk.Servlet.UploadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UploadServlet</servlet-name>
<url-pattern>/upload</url-pattern>
</servlet-mapping>
</web-app>
(6)实现结果截图
三、文件上传的细节
1、细节一:普通字段中文乱码问题
解决上传的时候, 普通的输入项(普通字段)中文的乱码问题
//Stringvalue = fileItem.getString();
//1.解决普通字段的中文乱码问题
String value = fileItem.getString("utf-8");
2、细节二:文件的中文名问题
解决上传的时候, 中文文件名的乱码
parse.setHeaderEncoding("utf-8");
如果不添加这个代码, 那么 上传的如果是中文文件名, 那么就会出现 文件名乱码的问题
3、细节三:设置临时缓冲区
上传时, 设置临时缓冲区文件所在的文件夹以及大小,是为了 加快 文件的上传的速度
在WebRoot目录下创建一个temp目录
//3.设置临时缓冲区:文件所在的文件夹以及大小;为了加快文件的上传速度
//临时缓冲区位置:/temp目录下
factory.setRepository(new File(this.getServletContext().getRealPath("/temp")));
factory.setSizeThreshold(1024*1024);//设置临时缓冲区的大小为1M
注意, 在文件上传完成后, 需要将 临时 文件给删除 .
这个代码需要放在 io 流关闭后 .
//关闭流
in.close();
out.close();
//3.将上传时产生的临时文件删除掉
fileItem.delete();
4、细节四:设置保存文件位置
上传的时候, 通常文件都会保存到 web 应用相对应文件夹下. 一般 会放到WEB-INF文件夹下,这样,外界就不能直接通过浏览器去访问到
为什么不让 外界直接访问呢 ?
防止恶意攻击,需要将上传的文件给保护起来, 那么就需要放到 WEB-INF文件夹下...
在WeB-INF文件夹下创建一个upload目录
//4.上传的时候,通常将文件保存在web应用相对应的文件夹下
//原因:外界无法访问到WEB-INF文件夹下的内容【防恶意攻击,将上传的文件保护起来】
Stringpath=this.getServletContext().getRealPath("/WEB-INF/upload");//所有上传文件都在upload目录下
File file=new File(path);
将文件保存到 WEB-INF目录下的 子文件夹下...
原因:外界无法访问到WEB-INF文件夹下的内容(假如里面有aaa.txt文件)
假如当前工程名为shop
使用者想访问shop下的aaa.txt文件
通过http://localhost:8080/WEB-IN/aaa.txt方式是访问不到的。
5、细节五:判断当前文件上传请求
判断一个请求是否是文件上传的请求
//5.判断一个请求是否是上传文件的请求;如果不是,给用户一个友好的提示【静态方法】
if(!ServletFileUpload.isMultipartContent(request)){
request.setAttribute("message", "对不起,不是文件上传的表单,请检查相关属性的设置");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
6、细节六:限制文件上传的大小
文件上传时, 限定上传的文件的大小.
例如,超过了 2M, 就不让上传... 超过了10 M, 就不让上传...
还会有 限定多张 照片上传时, 设置 总的大小
//6.限制上传的文件大小【超过了不让上传】
parse.setFileSizeMax(1024*1024*2);//2M 设置单个的上传文件的大小
parse.setSizeMax(1024*1024*20);//20M 设置总的上传的文件的大小
//超出时,抛出的异常写法
catch(FileUploadBase.FileSizeLimitExceededExceptione){
request.setAttribute("message", "对不起,单个文件的大小不能超过2M");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}catch(FileUploadBase.SizeLimitExceededExceptione){
request.setAttribute("message", "对不起,总的文件的大小不能超过20M");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
7、细节七:限制文件类型
可以去限制 上传的文件的类型
对文件的后缀名进行获取并判断,是否符合要求
//7.定义指定类型的后缀名,然后限制不在该范围内的后缀名
//String[]late={".txt",".doc",".jpg",".jpeg",".properties",".wmv"};
String[] late={"txt","doc","jpg","jpeg","properties","mv"};
//7.对文件的后缀名进行获取并且判断,是否符合要求,从而限制文件的上传类型
//获取文件名的"."的位置
// int lastindex=name.lastIndexOf('.');
int lastindex=name.lastIndexOf(".");
StringlateName=name.substring(lastindex+1);//后缀名
//将允许的后缀名数组转为字符串
String lateStr=Arrays.toString(late);
if(!lateStr.contains(lateName)){
//当前后缀名不是允许的后缀名,进行信息提醒
request.setAttribute("message", "该文件上传类型不符合要求,请长传其它类型的文件");
request.getRequestDispatcher("/message.jsp").forward(request, response);
System.out.println("文件类型错误。。。。失败。。。。。。。。。。。。。。。。。。。。");
// return;
}
8、细节八:文件名的浏览器兼容问题
例如: aaa.txt
上传的时候, 针对 不同的浏览器 ,获得文件的名字也是不一样的. 有些浏览器 上传的时候, 最终服务器端获得的文件的名字 是 aaa.txt, 但是有些浏览器 就是C:\Users\Administrator\Desktop\aaa.txt
因为上传文件时,浏览器有些显示了硬盘上文件所在的绝对路径名(IE浏览器),有些显示了文件名(360浏览器);因此在获得文件名的时候,也存在两种情况,有的浏览器所获得文件名有的是文件名(aaa.txt),有的则是绝对路径名(C:\Users\Administrator\Desktop\aaa.txt),为了充分考虑这些可能的情况,我们要对获取的文件名进行处理,从而统一要求。
处理方式:增加文件名的判断处理【将绝对路径名 变为 文件名】
//8.对文件名进行处理 因为有些浏览器中文件名:C:\Users\Administrator\Desktop\aaa.txt或者aa.txt
//所以需要对前面这种情况(C:\Users\Administrator\Desktop\aaa.txt)进行处理,
//进行文件名的提取,让它不包括路径
int wei=name.lastIndexOf('\\');
if(wei!=-1){
name=name.substring(wei+1);//转为最终的文件名 aa.txt
}
9、细节九:文件打开过慢问题
通常情况下,我们是将上传的文件放到 WEB-INF目录下的 upload文件夹下, 保护起来,不让外界直接访问.
为了避免上传的文件 都放在同一个文件夹下, 通常需要将 上传的文件打散的放到 多个文件夹 下, 这样可以有效的避免。
因为文件夹的文件过多而导致 文件夹打开过慢的问题
对于window 平台下, 微软 一般建议 一个文件夹的文件不要超过1000个.
通过拿到文件名的hashCode和二进制数:0000 0000 0000 1111进行位运算,来生成随机文件夹、
//9.生成随机文件夹
private String generateRandomPath(Stringpath, String name) {
//9.通过那到文件名的hashCode和二进制:0000 0000 0000 1111进行位运算,生成随机文件夹
// intfirst=name.hashCode()&(0000000000001111);
// intsecond=name.hashCode()&(0000000011110000);
//文件名哈希值
int hashCode=name.hashCode();
int first=hashCode&(0xf);
int second=(hashCode>>4)&(0xf);
String savePath=path+"/"+first+"/"+second;//保存目录
File f=new File(savePath);
if(!f.exists()){
f.mkdirs();//创建多级目录
}
return savePath;
}
10、细节十:文件名唯一问题
上传的过程中, 为了 避免同名的文件被覆盖的问题, 所以保存文件的时候, 要生成一个全球唯一的名字, 然后保存 到硬盘上去,这样可以有效 避免 同名文件被覆盖 ...
UUID的使用,给文件名添加前缀,保证每个文件名存入的时候是唯一的。
//10.保证上传文件的名字唯一
private String generateUUid(Stringname) {
String uuidName=UUID.randomUUID().toString()+"_"+name;
return uuidName;
}
11、细节十一:监听上传进度
监听上传进度
设置了一个进度监听器,设置了之后,解析器就会自动去调用监听器的方法update
//11.设置一个进度监听器,设置了之后,解析器就会自动去调用监听器的方法
parse.setProgressListener(new ProgressListener(){
//pBytesRead,当前读到的数据是多少
//pContentLength,当前解析到的fileItem的长度是多少
//pItems当前解析到第几个item了
private long megaBytes=-1;
@Override
public void update(long pBytesRead, long pContentLength,
int pItems) {
//第一次 : 400000 ------- 0 ---0 megaBytes 0
//第二次 : 800000 ------- 0 ---0megaBytes0
//第三次 : 1100000 ------- 1 ---1megaBytes1
//第四次 : 1900000 ------- 1 ---1megaBytes1
//第五次 : 2200000 ------- 2 ---2megaBytes2
long mBytes =pBytesRead / 1000000;// 0 0 1 1 2
if (megaBytes == mBytes) { //相等? 否 是 否 是 否
//(1)-1==0 (2)0==0 (3)0==1 (4)1==1 (5)1==2
return;
}
megaBytes = mBytes;
System.out.println("We are currently reading item "
+pItems);//正在读
if(pContentLength == -1) {
System.out.println("So far, " + pBytesRead
+ " bytes have been read.");
} else {
System.out.println("So far, " + pBytesRead + " of "
+pContentLength + "bytes have been read.");//已经读完
}
}
});
四、文件上传(添加细节后)
(1)说明
【1】只需把简单文件上传的中的UploadServlet 改为了UploadServletmore
【2】然后,再在index.jsp中将表单提交动作改为:uploadMore(UploadServletmore的映射路径),即:表单的action改为如下这样代码:
<formaction="${pageContext.request.contextPath }/uploadMore"method="post" enctype="multipart/form-data">
【3】web.xml中UploadServletmore的对外访问配置路径设置为:/UploadServletmore
【4】这样就可以处理一些文件上传的细节问题
(2)UploadServletmore代码
package com.zhku.jsj144.zk.Servlet;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
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.FileUploadBase;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
public class UploadServletmore extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
//7.定义指定类型的后缀名,然后限制不在该范围内的后缀名
// String[] late={".txt",".doc",".jpg",".jpeg",".properties",".wmv"};
String[] late={"txt","doc","jpg","jpeg","properties","mv"};
//5.判断一个请求是否是上传文件的请求;如果不是,给用户一个友好的提示【静态方法】
if(!ServletFileUpload.isMultipartContent(request)){
request.setAttribute("message", "对不起,不是文件上传的表单,请检查相关属性的设置");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
DiskFileItemFactory factory=new DiskFileItemFactory();
//3.设置临时缓冲区:文件所在的文件夹以及大小;为了加快文件的上传速度
//临时缓冲区位置:/temp目录下
factory.setRepository(new File(this.getServletContext().getRealPath("/temp")));
factory.setSizeThreshold(1024*1024);//设置临时缓冲区的大小为1M
//解析器
ServletFileUpload parse=new ServletFileUpload(factory);
//6.限制上传的文件大小【超过了不让上传】
parse.setFileSizeMax(1024*1024*2);//2M 设置单个的上传文件的大小
parse.setSizeMax(1024*1024*20);//20M 设置总的上传的文件的大小
//11.设置一个进度监听器,设置了之后,解析器就会自动去调用监听器的方法
parse.setProgressListener(new ProgressListener(){
//pBytesRead, 当前读到的数据是多少
//pContentLength,当前解析到的fileItem的长度是多少
//pItems 当前解析到第几个item了
private long megaBytes=-1;
@Override
public void update(long pBytesRead, long pContentLength,
int pItems) {
//第一次 : 400000 ------- 0 ---0 megaBytes 0
//第二次 : 800000 ------- 0 ---0 megaBytes 0
//第三次 : 1100000 ------- 1 ---1 megaBytes 1
//第四次 : 1900000 ------- 1 ---1 megaBytes 1
//第五次 : 2200000 ------- 2 ---2 megaBytes 2
long mBytes = pBytesRead / 1000000;// 0 0 1 1 2
if (megaBytes == mBytes) { //相等? 否 是 否 是 否
//(1)-1==0 (2)0==0 (3)0==1 (4)1==1 (5)1==2
return;
}
megaBytes = mBytes;
System.out.println("We are currently reading item "
+ pItems);//正在读
if (pContentLength == -1) {
System.out.println("So far, " + pBytesRead
+ " bytes have been read.");
} else {
System.out.println("So far, " + pBytesRead + " of "
+ pContentLength + " bytes have been read.");//已经读完
}
}
});
//2.解决文件名的乱码问题
parse.setHeaderEncoding("utf-8");
List<FileItem> list= parse.parseRequest(request);//获得解析器
for (FileItem fileItem : list) {
//普通字段
if(fileItem.isFormField()){
String fieldName = fileItem.getFieldName();
// //String value = fileItem.getString();
//1.解决普通字段的中文乱码问题
String value = fileItem.getString("utf-8");
System.out.println("fieldName:"+fieldName);
System.out.println("value:"+value);
}
//文件
else{
String name = fileItem.getName();//文件名
//7.对文件的后缀名进行获取并且判断,是否符合要求,从而限制文件的上传类型
//获取文件名的"."的位置
// int lastindex=name.lastIndexOf('.');
int lastindex=name.lastIndexOf(".");
String lateName=name.substring(lastindex+1);//后缀名
//将允许的后缀名数组转为字符串
String lateStr=Arrays.toString(late);
if(!lateStr.contains(lateName)){
//当前后缀名不是允许的后缀名,进行信息提醒
request.setAttribute("message", "该文件上传类型不符合要求,请长传其它类型的文件");
request.getRequestDispatcher("/message.jsp").forward(request, response);
System.out.println("文件类型错误。。。。失败。。。。。。。。。。。。。。。。。。。。");
// return;
}
//8.对文件名进行处理 因为有些浏览器中文件名:C:\Users\Administrator\Desktop\aaa.txt或者aa.txt
//所以需要对前面这种情况(C:\Users\Administrator\Desktop\aaa.txt)进行处理,
//进行文件名的提取,让它不包括路径
int wei=name.lastIndexOf('\\');
if(wei!=-1){
name=name.substring(wei+1);//转为最终的文件名 aa.txt
}
InputStream in = fileItem.getInputStream();
//4.上传的时候,通常将文件保存在web应用相对应的文件夹下
//原因:外界无法访问到WEB-INF文件夹下的内容【防恶意攻击,将上传的文件保护起来】
String path=this.getServletContext().getRealPath("/WEB-INF/upload");//所有上传文件都在upload目录下
//9.生成随机文件夹
String savePath=generateRandomPath(path,name);
//10.保证上传文件的名字唯一
String uuidName=generateUUid(name);
//路径:E:\apache-tomcat-7.0.73\webapps\Upload_download\WEB-INF\info.txt
// OutputStream out=new FileOutputStream(file.getAbsoluteFile()+"/"+name);
OutputStream out=new FileOutputStream(new File(savePath,uuidName));
//
// OutputStream out=new FileOutputStream("d:\\"+name);
byte[] buf=new byte[1024];
int len=0;
while((len=in.read(buf))!=-1){
out.write(buf, 0, len);
}
//关闭流
in.close();
out.close();
//3.将上传时产生的临时文件删除掉
fileItem.delete();
}
}
request.setAttribute("message", "文件上传成功");
request.getRequestDispatcher("/message.jsp").forward(request, response);
} catch(FileUploadBase.FileSizeLimitExceededException e){
request.setAttribute("message", "对不起,单个文件的大小不能超过2M");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}catch(FileUploadBase.SizeLimitExceededException e){
request.setAttribute("message", "对不起,总的文件的大小不能超过20M");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
//catch (FileUploadException e) {
catch (Exception e) {
e.printStackTrace();
// request.setAttribute("message", "文件上传失败");
// request.getRequestDispatcher("/message.jsp").forward(request, response);
}
}
//10.保证上传文件的名字唯一
private String generateUUid(String name) {
String uuidName=UUID.randomUUID().toString()+"_"+name;
return uuidName;
}
//9.生成随机文件夹
private String generateRandomPath(String path, String name) {
//9.通过那到文件名的hashCode和二进制:0000 0000 0000 1111进行位运算,生成随机文件夹
// int first=name.hashCode()&(0000000000001111);
// int second=name.hashCode()&(0000000011110000);
//文件名哈希值
int hashCode=name.hashCode();
int first=hashCode&(0xf);
int second=(hashCode>>4)&(0xf);
String savePath=path+"/"+first+"/"+second;//保存目录
File f=new File(savePath);
if(!f.exists()){
f.mkdirs();//创建多级目录
}
return savePath;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
五、文件的下载
你只需要去在用户点击了某个具体的链接 之后, 通知浏览器以 下载文件的方式去打开文件就可以了.
如何控制浏览器 以 下载文件的方式打开文件呢?
设置相应的 http响应头,如下:
//通知浏览器以下载的方式打开文件
response.setHeader("content-disposition","attachement;filename="+filename);
//还需要将 要下载的文件当作一个 inputStream 流读进来,
// 读进来再写到 response.getOutputStream中去就可以了.
六、简单文件下载
(1)下载文件页面index.jsp
<%@ page language="java" import="java.util.*"pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
下载文件<a href="/Upload_download/download?file=aa.txt">aa.txt</a>
</body>
</html>
(2)下载文件DownloadServlet
package com.zhku.jsj144.zk.Servlet;
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;
// 下载d:/aa.txt 特定文件的实现
public class DownloadServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//file=aaa.txt
String file = request.getParameter("file");
System.out.println(file);
File f=new File("d:/"+file);//要下载的文件存存放位置
String filename =URLEncoder.encode(file, "utf-8");//给文件名编码
//将中文的 文件名 编码 后 再 放到 http的响应头 中去 , 编码 之后 浏览器 收到 后 会自动的解码
//通知浏览器以下载的方式打开文件
response.setHeader("content-disposition", "attachement;filename="+filename);
//还需要将 要下载的 文件 当作 一个 inputStream 流 读进来,
// 读进来 再 写到 response.getOutputStream中去就可以了.
InputStream in=new FileInputStream(f);//文件
OutputStream out=response.getOutputStream();
byte[] buf=new byte[1024];
int len=0;
while((len=in.read(buf))!=-1){
out.write(buf, 0, len);
}
in.close();
out.close();
System.out.println("下载文件成功");
// response.getWriter().write("下载文件成功");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
(3)说明
点击页面index.jsp,即可实现d盘下的aa.txt文件的下载【注意:d盘下必须要有aa.txt文件】
七、实现源码
实现源码
(1)简单文件上传
(2)文件上传(添加细节后)
(3)简单文件下载
可看本人的github项目地址:
https://github.com/Forever99/Upload_download