文件上传下载概述
1、什么是文件上传下载
所谓文件上传下载就是将本地文件上传到服务器端,从服务器端下载文件到本地的过程。
例如目前网站需要上传头像、上传下载图片或网盘等功能都是利用文件上传下载功能实现的。
文件上传下载实际上是两步操作,
第一是文件上传,就是将本地文件上传到服务器端,实现文件多用户之间的共享,
第二是文件下载,就是将服务器端的文件下载到本地磁盘。
2.文件上传下载实现原理
上传:
文件上传实现流程如下:
Ø 客户端浏览器通过文件浏览框,选择需要上传的文件内容(其中包括文件路径及文件内容)。
Ø 客户端浏览器通过点击上传按钮,将本地文件上传到服务器端。
Ø 服务器端通过程序接收本地文件内容,并将其保存在服务器端磁盘中。
下载:
文件下载实现流程如下:
Ø 客户端浏览器通过点击下载按钮,将服务器端保存的文件下载到本地磁盘。
Ø 服务器端通过程序将服务器端文件响应给客户端。
3、实现上传
文件上传到客户端页面:
在Web应用程序中实现文件上传功能,只需要在客户端页面中添加需要上传输入项,在服务器端Servlet中读取上传文件的数据,并保存在服务器端硬盘中即可。
需要注意的是:
Ø 文件上传域(<input type='file'>)必须具有name属性.:
<inputtype=”file”>标签必须指定name属性值,否则需要上传的文件数据是不会上传至服务器端。
Ø 请求方式一定是POST.:
完成文件上传功能的表单的请求类型必须是POST方式。
Ø 表单的enctype属性值设置为"multipart/form-data".
完成文件上传功能的表单的enctype属性值设置为“multipart/form-data”,该值的作用是将需要上传的文件数据添加到Http请求体中,并使用MIME协议对上传的文件进行描述。
<body>
<form action="" method="post" enctype="multipart/form-data">
文件描述:<input type="text" name="filetext"><br>
<input type="file" name="upload"><br>
<input type="submit" value="上传">
</form>
</body>
commons-fileupload工具
完成客户端的文件上传功能之后,主要是在服务器端完成接收上传文件的数据内容。为了方便实现文件上传逻辑,可以使用第三方提供的文件上传包,具体如下:
Ø jsp-smartupload.jar:使用JSP模型一时使用的,目前基本不再使用。
Ø commons-fileupload.jar:由Apache基金会提供的,用来实现Java环境下的文件上传功能。
Ø Servlet3.0规范中提供对文件上传的支持。
commons-fileupload组件的官网地址:http://commons.apache.org/proper/commons-fileupload/。需要注意的是:在使用commons-fileupload组件时,需要依赖于commons-io包。commons-fileupload组件工作流程如下:
实现文件上传的服务器端:
package upload;
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 org.apache.commons.io.IOUtils;
//完成文件上传功能
public class UploadServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1.创建文件上传的工厂类实例对象
DiskFileItemFactory factory = new DiskFileItemFactory();
//2.创建文件上传的servletFileUpload实例对象
ServletFileUpload upload = new ServletFileUpload(factory);
try {
//3.利用ServletFileUpload实例对象解析request对象中有关文件上传的内容(文件上传的内容都封装在了request对象中了)
List<FileItem> items = upload.parseRequest(request);
//4.遍历文件上传到的list集合,得到有关文件上传到的所有内容(普通字段和上传内容)
for (FileItem fileItem : items) {
/*
* 如何可以知道当前的FileItem是普通项还是文件项
* *通过FileItem.isFormField()方法判断当前是普通项还是文件项
* *结果是true的话,表示当前是普通项
* *结果是false的话,表示当前是文件项
*/
if(fileItem.isFormField()){
//普通项
/*getFieldName():获取普通项的name属性值
*getString(): 获取普通项的文本内容
*/
String fieldName = fileItem.getFieldName();
String fieldValue = fileItem.getString();
System.out.println(fieldName+":"+fieldValue); //filetext : readme
}else{
//文件项
/*getName():获取文件项的上传文件名称
*getInputStream(): 获取文件项的上传文件输入流
*/
String fileName = fileItem.getName();
System.out.println(fileName);//readme.txt
InputStream in = fileItem.getInputStream();
String realPath = getServletContext().getRealPath("/uploads");
OutputStream out = new FileOutputStream(new File(realPath,fileName));
IOUtils.copy(in, out);
in.close();
out.close();
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
upload.jsp:
<body>
<form action="${pageContext.request.contextPath }/servlet/UploadServlet" method="post" enctype="multipart/form-data">
文件描述:<input type="text" name="filetext"><br>
<input type="file" name="upload"><br>
<input type="submit" value="上传">
</form>
</body>
实现的步骤:
* 实例化DiskFileItemFactory工厂类.
* 实例化ServletFileUpload类.
ServletFileUpload upload = new ServletFileUpload(factory);
* 利用upload的parseRequest(request)方法从Request对象中获取文件上传的内容(List集合).
* 遍历获取到的List集合.
* 如果是普通项 - 获取普通项的文本内容.
* isFormField():判断当前是否是普通项,true表示是.
* getFieldName():获取普通项的name属性值.
* getString():获取普通项的文本内容.
* 如果是文件项
* getName():获取上传文件的名称.
* getInputStream():获取上传文件的输入流.
* 通过保存的路径,创建文件的输出流.
* 利用IOUtils.copy(inputStream,OutputStream)方法将上传文件进行保存.(在服务器中查看)
动态多文件上传表单
<script type="text/javascript">
function addFileItem() {
document.getElementById("showFile").innerHTML+="<div><input type='file' name='upload'>
<input type='button' id='delFile' οnclick='delFileItem(this);' value='删除'><br></div>";
}
function delFileItem(button) {
var parentDiv = button.parentNode;
parentDiv.parentNode.removeChild(parentDiv);
}
</script>
<body>
<form action="${pageContext.request.contextPath }/servlet/UploadServlet" method="post" enctype="multipart/form-data">
<input type="button" id="addFile" οnclick="addFileItem();" value="文件上传"><br>
<div id="showFile"></div>
<input type="submit" value="上传">
</form>
</body>
上传文件至WEB-INF目录
到目前步骤,已经可以成功从客户端浏览器向服务器端上传文件。但是上传的路径存在一些问题,上述上传路径是自定义的文件夹,而上传至这种自定义的文件夹后,通过浏览器可以正常访问,这是非常危险的。
例如一个用户上传一个JSP页面,然后通过浏览器访问该JSP页面,而该JSP页面中可以包含一些恶意代码。这时如果允许用户运行该JSP页面的话,可能会对服务器端造成很大影响。
所以,通常情况下,会将上传目录创建在Web工程的WEB-INF目录下。因为该目录下的内容,是无法通过浏览器访问到的。
* WEN-INF目录外:在浏览器中可以访问的(安全低).
* WEB-INF目录中:在浏览器中不能访问的.
String uploadPath =getServletContext().getRealPath("/WEB-INF/upload");
上传文件名称的处理
String fileName = fileItem.getName();
//解决浏览器过旧的问题:上传文件名的处理 :C:\Users\JYL\Desktop\day0106\笔记\readme.txt
int index = fileName.lastIndexOf("\\");
if(index>=0){
fileName.substring(index+1);
}
上传文件同名问题的处理
解决:将每个上传的文件名,提供一个唯一的标识(拼在文件名中).
fileName = UUID.randomUUID().toString()+fileName;
注意:如果开发真实案例时,需要保存真实文件名称和上传后处理的文件名称.
//为了防止文件同名,给文件名增加一个唯一的id
fileName = UUID.randomUUID().toString()+fileName;
上传文件中文乱码问题
如果现在上传文件的名称为中文的话,会引起中文乱码问题。commons-fileupload组件为解决中文乱码问题提供了两种解决方案,如下:
Ø 利用Request对象的setCharacterEncoding(“UTF-8”)方法,该方法尽量编写在Servlet的doGet()或doPost()方法的顶端。
Ø 利用ServletFileUpload类提供的setHeaderEncdoing(“UTF-8”)方法来解决。
一般情况下,不关心上传文件的内容,因为上传文件会保存在服务器端的磁盘中。但是,如果需要在控制台打印上传文件的内容,而刚好该上传文件的内容中包含中文的话,可以使用FileItem的getString(“UTF-8”)来处理编码。
一个目录不能存放过多文件
如果上传文件过多时,会导致上传目录中的文件过多,内容过大。这时可以考虑将不同文件存储在不同的目录中,而生成不同目录的规则参考如下:
Ø 按照上传时间进行目录分离,例如2014-12-12为一个目录。
Ø 按照上传用户进行目录分离,为每一个用户创建一个上传目录。
Ø 按照固定数量进行目录分离,设定当一个上传目录包含文件超过指定数量,创建新的上传目录。
Ø 按照唯一文件名的hashcode进行目录分离。
这里以hashcode进行目录分离方式为例演示,具体思路如下:
Ø 使用UUID类的randomUUID()方法生成唯一标识符。
name = UUID.randomUUID().toString() + "_" + name;
其值为2dab369c-1e4f-4e58-8b61-13c7aef855b0。
Ø 通过hashCode()方法获取其唯一标识符的hashcode值。
int hashcode = uuidFileName.hashCode();
其值为:166846237,转换成二进制后的值为:1001111100011101111100011101。
Ø 按照每4位值“与”二进制1111(F)后,生成一级目录。
// 获得一级目录
int d1 = hashcode & 0xf;
Ø 以此类推,每4位值“与”二进制1111后,生成一个级别的目录。
// 获得二级目录
int d2 = (hashcode >>> 4) & 0xf;
根据上述步骤,可以编写一个按照hashcode方式生成目录的工具类,具体代码如下:
public class UploadUtils {
// 根据唯一文件名生成 hashcode目录分离算法
public static String generateRandomDir(String uuidFileName) {
// 获得唯一文件名的hashcode
int hashcode = uuidFileName.hashCode();
// 获得一级目录
int d1 = hashcode & 0xf;
// 获得二级目录
int d2 = (hashcode >>> 4) & 0xf;
return "/" + d2 + "/" + d1;
}
}
上述程序代码可以改写如下:
String randomDir = UploadUtils.generateRandomDir(name);
String uploadPath = getServletContext().getRealPath("/WEB-INF/upload" + randomDir);
// 生成随机目录
new File(uploadPath).mkdir();
上传单个文件的大小限制
上传文件时,用户可能上传非常大的文件,可能导致上传时占用过多资源。所以,对于用户上传的单个文件大小,应做出相应限制。利用ServletFileUpload的setFileSizeMax(long)方法进行设置,其中参数表示设置的大小,单位为字节数,例如servletFileUpload.setFileSizeMax(1024*10)表示上限为10KB。
一旦上传的单个文件大小超过限制大小时,会抛出FileUploadBase.FileSizeLimitExceededException异常,可以捕获该异常后向页面输出相应的错误信息。* 利用ServletFileUpload的setFileSizeMax(字节数).
* 问题:如果上传的单个文件大小,大于限制的大小时:抛异常.
FileSizeLimitExceededException
public class UploadServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
// 设置单个上传文件的大小
upload.setFileSizeMax(1024 * 10);
try {
List<FileItem> items = upload.parseRequest(request);
for (FileItem fileItem : items) {
if (fileItem.isFormField()) {
……
}else{
String name = fileItem.getName();
……
in.close();
}
}
} catch (FileUploadException e) {
if (e instanceof FileUploadBase.FileSizeLimitExceededException) {
// 在request中保存错误信息
request.setAttribute("msg", "上传失败!上传的文件超出了10KB!");
// 转发到index.jsp页面中!在index.jsp页面中需要使用${msg}来显示错误信息
request.getRequestDispatcher("/index.jsp").forward(request, response);
}
e.printStackTrace();
}
}
}
上传文件的总大小的限制
在实现多文件上传时,还需要设置上传文件的总大小。利用ServletFileUpload的setSizeMax(long)方法进行设置,其中参数表示设置的大小,单位为字节数,例如servletFileUpload.setSizeMax(1024*10)表示上限为10KB。
一旦上传的文件大小超过限制大小时,会抛出FileUploadBase.SizeLimitExceededException异常,可以捕获该异常后向页面输出相应的错误信息。public class UploadServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
// 设置单个上传文件的大小
upload.setSizeMax(1024 * 10);
try {
List<FileItem> items = upload.parseRequest(request);
for (FileItem fileItem : items) {
if (fileItem.isFormField()) {
……
}else{
String name = fileItem.getName();
……
in.close();
}
}
} catch (FileUploadException e) {
if (e instanceof FileUploadBase.SizeLimitExceededException) {
// 在request中保存错误信息
request.setAttribute("msg", "上传失败!上传的文件超出了10KB!");
// 转发到index.jsp页面中!在index.jsp页面中需要使用${msg}来显示错误信息
request.getRequestDispatcher("/index.jsp").forward(request, response);
}
e.printStackTrace();
}
}
}
文件缓存大小与临时目录
一般情况下,上传文件默认都是先存储在内存中,然后在拷贝到服务器端的磁盘中。但是这样会有一些问题出现,例如单个文件过大时,占用服务器端资源会过多,导致服务器性能变差。这时可以通过手动设置文件缓存大小和上传文件的临时目录来解决。如果不设置上传的文件缓存大小,默认值为10KB,其表示如果上传文件小于10KB的话,会先存储在服务器端的内存中,如果上传文件大小大于10KB的话,会先存储在服务器端默认指定的临时目录中,而上传文件的默认临时目录为System.getProperty("java.io.tmpdir")。
手动修改上传文件缓存大小及临时目录的方式如下:
Ø 手动修改上传文件缓存大小:DiskFileItemFactory.setSizeThreshold(缓存字节数);
Ø 手动修改上传文件临时目录:
DiskFileItemFactory.setRepository(newFile(getServletContext().getRealPath(临时目录相对路径)));
想要删除临时目录下的临时文件的话,只需要调用FileItem的delete()方法即可。
上传文件的缓存文件大小与临时目录:
* 默认情况下:上传文件的输入流存储在服务器端的内存中(缓存).
* 问题:
* 当上传的单个文件过大时,导致服务器端的内存空间不足(性能下降)
* 解决:
* 指定上传文件的缓存大小.
* 如果上传文件的缓存大于指定的缓存(内存中)大小,使用临时文件(硬盘中)的方式.
* 如何实现:
* 指定上传的缓存大小:
* factory.setSizeThreshold(1024*1024);
* 设置上传临时目录:
* factory.setRepository(new File(getServletContext().getRealPath("/tmp")));
* 机制:当文件上传成功后,删除临时目录中的临时文件.
fileItem.delete();
* 上传文件比较大时,上传的速度变慢?
* 原因就是输入流与输出流的问题.
* 输出流:new BufferedOutputStream(new FileOutputStream(new File(realPath,fileName)));
* 输入流:new BufferedInputStream(fileItem.getInputStream());
public class UploadServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
DiskFileItemFactory factory = new DiskFileItemFactory();
// 内存缓冲区
factory.setSizeThreshold(3 * 1024 * 1024); // 3M
// 临时文件位置
File repository = new File(getServletContext().getRealPath("/tmp"));
factory.setRepository(repository);
ServletFileUpload upload = new ServletFileUpload(factory);
try {
List<FileItem> items = upload.parseRequest(request);
for (FileItem fileItem : items) {
if (fileItem.isFormField()) {
……
}else{
String name = fileItem.getName();
……
in.close();
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
}
文件上传进度监听器
目前大部分具有文件上传功能的,在文件上传过程中,可以实时看到上传进度。可以使用ServletFileUpload提供的setProgressListener()方法实现,在客户端配置Ajax技术即可实现。由于目前没有掌握Ajax异步交互技术,所以只能在服务器端完成查看进度功能。
其中除使用setProgressListener()方法实现外,还需要计算如下几个结果:
Ø 已用时间:当前时间 – 开始时间
Ø 速度:已经上传大小/ 已用时间
Ø 剩余大小:总大小 – 已经上传大小
Ø 剩余时间:剩余大小/ 速度
根据上述内容,具体查看上传进度功能如下:
//获取上传文件的开始时间
final long start = System.currentTimeMillis();
//为文件上传对象,帮助查看进度监听器
upload.setProgressListener(new ProgressListener() {
/*
* update(long pBytesRead, long pContentLength, int pItems)
* * 该方法用于获取文件上传过程相关数据内容.
* * 参数pBytesRead:到目前为止已经读取字节总数(已上传大小)
* * 参数pContentLength:正在上传字节总数 (文件大小)
* * 参数pItems:当前上传文件,是表单的第几个元素
*/
public void update(long pBytesRead, long pContentLength, int pItems) {
if(pBytesRead == 0){
// 刚开始上传,还没有数据
return;
}
// 计算已经使用时间
long hasUseTime = System.currentTimeMillis() - start;
// 计算上传速度
double speed = ((double)pBytesRead) / hasUseTime;
// 计算剩余大小
long restBytes = pContentLength - pBytesRead;
// 计算剩余时间
long restTime = (long) (restBytes / speed);
System.out.println("已用时间:" + hasUseTime + ", 传输速度:" + speed + ", 剩余时间:" + restTime);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
* 上传文件比较大时,上传的速度变慢?
* 原因就是输入流与输出流的问题.
* 输出流:new BufferedOutputStream(new FileOutputStream(new File(realPath,fileName)));
* 输入流:new BufferedInputStream(fileItem.getInputStream());
* 文件上传的进度条的功能:
* 服务器端:监听文件上传的整个过程(从开始上传到上传结束)
* 需要文件上传的监听器.
//为文件上传的过程,增加监听器(监听文件上传的过程)
upload.setProgressListener(new ProgressListener() {
/*
* update(long pBytesRead, long pContentLength, int pItems)
* 作用:用于监听文件上传过程的状态信息
* 参数:
* pBytesRead:到目前为止,已经读取上传文件的大小
* pContentLength:上传文件的总大小
* pItems:当前上传文件,是表单的第几个元素
*
* 计算以下四个结果:
* *已用时间:当前时间 - 开始时间
* *上传速度:已经上传大小/已用时间
* *剩余大小:总大小 - 已经上传的大小
* *剩余时间:剩余大小 /速度
*/
@Override
public void update(long pBytesRead, long pContentLength, int pItems) {
//获取文件上传的当前时间
long currentTime = System.currentTimeMillis();
//已用时间:当前时间 - 开始时间
long useTime = currentTime - startTime;
//上传速度:已经上传大小/已用时间
long speed = pBytesRead / useTime;
//剩余大小:总大小 - 已经上传的大小
long restBytes = pContentLength - pBytesRead;
//剩余时间:剩余大小 /速度
long restTime = restBytes/speed;
}
});
最终的代码:
package upload;
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 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.ProgressListener;
import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;
//完成文件上传功能
public class UploadServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1.创建文件上传的工厂类实例对象
DiskFileItemFactory factory = new DiskFileItemFactory();
//设置上传文件的缓存大小
factory.setSizeThreshold(1024*1024);
//设置指定的临时文件存储的目录
factory.setRepository(new File(getServletContext().getRealPath("/tmp")));
//2.创建文件上传的servletFileUpload实例对象
ServletFileUpload upload = new ServletFileUpload(factory);
//获取当前时间,即文件开始上传的时间
final long startTime = System.currentTimeMillis();
//为文件上传的过程,增加监听器(监听文件上传的过程)
upload.setProgressListener(new ProgressListener() {
/*
* update(long pBytesRead, long pContentLength, int pItems)
* 作用:用于监听文件上传过程的状态信息
* 参数:
* pBytesRead:到目前为止,已经读取上传文件的大小
* pContentLength:上传文件的总大小
* pItems:当前上传文件,是表单的第几个元素
*
* 计算以下四个结果:
* *已用时间:当前时间 - 开始时间
* *上传速度:已经上传大小/已用时间
* *剩余大小:总大小 - 已经上传的大小
* *剩余时间:剩余大小 /速度
*/
@Override
public void update(long pBytesRead, long pContentLength, int pItems) {
//获取文件上传的当前时间
long currentTime = System.currentTimeMillis();
//已用时间:当前时间 - 开始时间
long useTime = currentTime - startTime;
//上传速度:已经上传大小/已用时间
long speed = pBytesRead / useTime;
//剩余大小:总大小 - 已经上传的大小
long restBytes = pContentLength - pBytesRead;
//剩余时间:剩余大小 /速度
long restTime = restBytes/speed;
}
});
try {
//限制单个文件上传的大小
upload.setFileSizeMax(1024*1024*3);//3M
//限制上传文件的总大小
upload.setSizeMax(1024*1024*10);
//3.利用ServletFileUpload实例对象解析request对象中有关文件上传的内容(文件上传的内容都封装在了request对象中了)
List<FileItem> items = upload.parseRequest(request);
//4.遍历文件上传到的list集合,得到有关文件上传到的所有内容(普通字段和上传内容)
for (FileItem fileItem : items) {
/*
* 如何可以知道当前的FileItem是普通项还是文件项
* *通过FileItem.isFormField()方法判断当前是普通项还是文件项
* *结果是true的话,表示当前是普通项
* *结果是false的话,表示当前是文件项
*/
if(fileItem.isFormField()){
//普通项
/*getFieldName():获取普通项的name属性值
*getString(): 获取普通项的文本内容
*/
String fieldName = fileItem.getFieldName();
String fieldValue = fileItem.getString();
System.out.println(fieldName+":"+fieldValue); //filetext : readme
}else{
//文件项
/*getName():获取文件项的上传文件名称
*getInputStream(): 获取文件项的上传文件输入流
*/
String fileName = fileItem.getName();
//解决浏览器过旧的问题:上传文件名的处理 :C:\Users\JYL\Desktop\day0106\笔记\readme.txt
int index = fileName.lastIndexOf("\\");
if(index>=0){
fileName.substring(index+1);
}
//fileName.substring(fileName.lastIndexOf("\\")+1);
//为了防止文件同名,给文件名增加一个唯一的id
fileName = UUID.randomUUID().toString()+fileName;
System.out.println(fileName);//readme.txt
InputStream in = fileItem.getInputStream();
//将上传目录进行分级处理
int hashcode = fileName.hashCode();
//生成一级目录
int d1 = hashcode & 0xf;
//生成二级目录
int d2 = (hashcode >>> 4) & 0xf;
String realPath = getServletContext().getRealPath("/WEB-INF/uploads/"+d1+"/"+d2);
new File(realPath).mkdirs();
OutputStream out = new FileOutputStream(new File(realPath,fileName));
IOUtils.copy(in, out);
in.close();
out.close();
}
}
} catch (Exception e) {
if(e instanceof FileSizeLimitExceededException){
System.out.println("你上传的文件过大,请压缩后再上传");
}
if(e instanceof SizeLimitExceededException){
System.out.println("你上传的文件总大小过大,请压缩后再上传");
}
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
扩展:浏览器内核产品不同(不建议使用IE)
* IE浏览器:IE6.0\7.0 IE8.0\9.0IE10\11
* 其他浏览器:Webkit(苹果)
* 苹果浏览器
* 火狐浏览器:自主内核产品.
* 谷歌浏览器:自主内核产品.
* 众多国内浏览器:
* 百度浏览器:号称自主内核.
* 腾讯浏览器:号称自主内核.
* 遨游浏览器:号称自主内核.
* 360\搜狗\猎豹等...