文件上传及几个细节问题
2014-02-17 23:23
281 查看
搭建网站时,有一个常用的功能就是文件的上传与下载。在添加一个文件上传功能时,主要有两个步骤:
1、创建一个web页面,填写需要上传文件的相关输入项
1.1通过<input type="file" />标签可以添加一个上传文件,需要注意的是,input标签一定要设置name属性,否则浏览器不会发送上传的文件数据。
1.2另外还需要把form标签的enctype属性设置成multipart/form-data,设置该值后,浏览器将会把文件数据附带在http请求消息体中,并使用MIME协议对上传文件进行描述,以方便接受方对上传文件进行解析和处理
2、创建一个servlet,负责解析上传过来的文件,读取并将其保存至硬盘中
2.1 request提供了一个getInputStream方法,可以获取到客户端提交过来的数据,但由于客户可能同时上传多个文件,在servelt上直接编程将会很麻烦。
2.2 apache组织提供一个用来处理表单文件上传的组件,该组件提供了性能优异的API,方便开发者实现表单文件上传功能。此组件名为:Commons-fileupload
3、使用Commons-fileupload组件,需要导入相关开发jar包,此jar包名为:
Commons-fileupload和commons-io, commons-io不属于文件上传组件的开发jar包,但Commons-fileupload从1.1版本后,需要其支持。
使用此开源组件,开发流程图如下:
4、Servlet核心开发步骤
4.1 创建一个DiskFileItemFactory工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
4.2 创建一个ServletFileUpload对象,此对象将封装对上传文件数据的处理操作
ServletFileUpload upload = new ServletFileUpload(factory);
4.3 通过ServletFileUpload的isMultipartContent方法判断是否是表单文件上传,否则按照正常方式处理
if (!upload.isMultipartContent(request)) {
// 安传统方式读取数据,即表单数据上传的数据 enctype="multipart/form-data"
return;
}
4.4 通过ServletFileUpload的parseRequest方法获取request提交的每项表单数据,每项表单数据将被封装在一个FileItem对象中
List<FileItem> list;
list = (List<FileItem>) upload.parseRequest(request);
4.5 处理每项表单数据,根据FileItem的isFormField方法来区分提交的数据是否是普通表单数据还是文件上传数据,若是文件上传数据,调用FileItem的getInputStream方法可以获取到上传文件的数据。
整体代码示例如下:
public class FileUploadServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// request是安装MIME协议传输,不能再以request.getParameter方式读取
String savePath = this.getServletContext().getRealPath(
"/WEB-INF/upload");
//1、解决表单名和上传文件名中文乱码问题
// request.setCharacterEncoding("UTF-8");
try {
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
//方法二:解决上传文件名中文乱码问题
upload.setHeaderEncoding("UTF-8");
if (!upload.isMultipartContent(request)) {
// 安传统方式读取数据,即表单数据上传的数据 enctype="multipart/form-data"
return;
}
//上传的数据时按照enctype="multipart/form-data"方式传上来的,其数据时按照MIME协议上传的
List<FileItem> list;
list = (List<FileItem>) upload.parseRequest(request);
for (FileItem item : list) {
if (item.isFormField()) {
String name = item.getFieldName();
//方法一:数据表单内容的中文乱码问题,按照multipart/form-data上传的数据,都按照iso8859-1进行编码
// 要解决此中文乱码问题,需要先对获取到的数据进行iso8859-1进行解码,在按照UTF-8进行编码
// String value = item.getString();
// value = new String(value.getBytes("iso8859-1"), "UTF-8");
//方法二:解决数据表单内容的中文乱码问题,采用FiltItem类中的getString(Charset)方法,此方法重载了getString
//获取到的数据将按照指定的编码方式进行编码
String value = item.getString("utf-8");
System.out.println(name + ":" + value);
} else {
String fileName = item.getName();
// 不同浏览器通过request上传的文件名不一致,有是完整路径,有点是文件名: c:\a\b\1.txt or
// 1.txt
fileName = fileName
.substring((fileName.lastIndexOf("\\") + 1));
InputStream in = item.getInputStream();
//FileOutputStream out = new FileOutputStream(savePath + "\\"
// + fileName);
//解决上传文件重名问题
String saveName = makeFileName(fileName);
// FileOutputStream out = new FileOutputStream(savePath + "\\"
// +saveName);
//文件打散算法
String realSavePath = makeSavePath(savePath, fileName);
FileOutputStream out = new FileOutputStream(realSavePath + "\\"
+saveName);
byte[] buf = new byte[1024];
int len = 0;
while ((len = in.read(buf)) > 0) {
out.write(buf);
}
out.close();
in.close();
}
}
} catch (FileUploadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
//解决上传文件重名导致文件覆盖问题
private String makeFileName(String fileName){
return UUID.randomUUID()+"_"+fileName;
}
//文件打散问题,解决一个文件下文件过多的问题
private String makeSavePath(String savePath, String fileName){
if(fileName==null || savePath==null){
return null;
}
int hCode = fileName.hashCode();
int dir1 = hCode&0x0f;
int dir2 = (hCode&0xf0)>>4;
String dir = savePath+"\\"+dir1+"\\"+dir2;
//文件要是不存在,创建此文件
File f = new File(dir);
if(!f.exists()){
f.mkdirs();
}
return dir;
}
}
5 上面的示例代码还解决了几个文件上传中的细节问题
5.1 表单名和上传文件名中文乱码问题
解决此问题有两种方法
一:通过request.setCharacterEncoding("UTF-8")来设置中文编码
二:通过ServletFileUpload的setHeaderEncoding方法来设置中文编码
ServletFileUpload upload = new ServletFileUpload(factory);
//方法二:解决上传文件名中文乱码问题
upload.setHeaderEncoding("UTF-8");
5.2 提交的表单内容中文乱码问题
由于设置了form标签的enctype属性值为multipart/form-data,其将通过MIME协议向服务器提交数据,所有表单数据都是通过iso8859-1来编码的。解决此中文乱码问题有两种方法
一:将表单数据通过iso8859-1进行解码,得到源字节码,在通过UTF-8编码
if (item.isFormField()) {
String name = item.getFieldName();
//方法一:数据表单内容的中文乱码问题,按照multipart/form-data上传的数据,都按照iso8859-1进行编码
// 要解决此中文乱码问题,需要先对获取到的数据进行iso8859-1进行解码,在按照UTF-8进行编码
// String value = item.getString();
// value = new String(value.getBytes("iso8859-1"), "UTF-8");
//方法二:解决数据表单内容的中文乱码问题,采用FiltItem类中的getString(Charset)方法,此方法重载了getString
//获取到的数据将按照指定的编码方式进行编码
String value = item.getString("utf-8");
System.out.println(name + ":" + value);
二:通过调用FileItem的getString(Charset charset)来获取表单内容。
5.3 上传文件重名问题
使用UUID方法重写文件名
//解决上传文件重名导致文件覆盖问题
private String makeFileName(String fileName){
return UUID.randomUUID()+"_"+fileName;
}
5.4 上传文件打散问题
使用文件名在内存中的地址(hashcode)来创建存储路径,总共两级目录,第一级目录名为filename 哈希值最低0-4位值,第二级目录名为哈希值低5-8位。
private String makeSavePath(String savePath, String fileName){
if(fileName==null || savePath==null){
return null;
}
int hCode = fileName.hashCode();
int dir1 = hCode&0x0f;
int dir2 = (hCode&0xf0)>>4;
String dir = savePath+"\\"+dir1+"\\"+dir2;
//文件要是不存在,创建此文件
File f = new File(dir);
if(!f.exists()){
f.mkdirs();
}
return dir;
}
1、创建一个web页面,填写需要上传文件的相关输入项
1.1通过<input type="file" />标签可以添加一个上传文件,需要注意的是,input标签一定要设置name属性,否则浏览器不会发送上传的文件数据。
1.2另外还需要把form标签的enctype属性设置成multipart/form-data,设置该值后,浏览器将会把文件数据附带在http请求消息体中,并使用MIME协议对上传文件进行描述,以方便接受方对上传文件进行解析和处理
2、创建一个servlet,负责解析上传过来的文件,读取并将其保存至硬盘中
2.1 request提供了一个getInputStream方法,可以获取到客户端提交过来的数据,但由于客户可能同时上传多个文件,在servelt上直接编程将会很麻烦。
2.2 apache组织提供一个用来处理表单文件上传的组件,该组件提供了性能优异的API,方便开发者实现表单文件上传功能。此组件名为:Commons-fileupload
3、使用Commons-fileupload组件,需要导入相关开发jar包,此jar包名为:
Commons-fileupload和commons-io, commons-io不属于文件上传组件的开发jar包,但Commons-fileupload从1.1版本后,需要其支持。
使用此开源组件,开发流程图如下:
4、Servlet核心开发步骤
4.1 创建一个DiskFileItemFactory工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
4.2 创建一个ServletFileUpload对象,此对象将封装对上传文件数据的处理操作
ServletFileUpload upload = new ServletFileUpload(factory);
4.3 通过ServletFileUpload的isMultipartContent方法判断是否是表单文件上传,否则按照正常方式处理
if (!upload.isMultipartContent(request)) {
// 安传统方式读取数据,即表单数据上传的数据 enctype="multipart/form-data"
return;
}
4.4 通过ServletFileUpload的parseRequest方法获取request提交的每项表单数据,每项表单数据将被封装在一个FileItem对象中
List<FileItem> list;
list = (List<FileItem>) upload.parseRequest(request);
4.5 处理每项表单数据,根据FileItem的isFormField方法来区分提交的数据是否是普通表单数据还是文件上传数据,若是文件上传数据,调用FileItem的getInputStream方法可以获取到上传文件的数据。
整体代码示例如下:
public class FileUploadServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// request是安装MIME协议传输,不能再以request.getParameter方式读取
String savePath = this.getServletContext().getRealPath(
"/WEB-INF/upload");
//1、解决表单名和上传文件名中文乱码问题
// request.setCharacterEncoding("UTF-8");
try {
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
//方法二:解决上传文件名中文乱码问题
upload.setHeaderEncoding("UTF-8");
if (!upload.isMultipartContent(request)) {
// 安传统方式读取数据,即表单数据上传的数据 enctype="multipart/form-data"
return;
}
//上传的数据时按照enctype="multipart/form-data"方式传上来的,其数据时按照MIME协议上传的
List<FileItem> list;
list = (List<FileItem>) upload.parseRequest(request);
for (FileItem item : list) {
if (item.isFormField()) {
String name = item.getFieldName();
//方法一:数据表单内容的中文乱码问题,按照multipart/form-data上传的数据,都按照iso8859-1进行编码
// 要解决此中文乱码问题,需要先对获取到的数据进行iso8859-1进行解码,在按照UTF-8进行编码
// String value = item.getString();
// value = new String(value.getBytes("iso8859-1"), "UTF-8");
//方法二:解决数据表单内容的中文乱码问题,采用FiltItem类中的getString(Charset)方法,此方法重载了getString
//获取到的数据将按照指定的编码方式进行编码
String value = item.getString("utf-8");
System.out.println(name + ":" + value);
} else {
String fileName = item.getName();
// 不同浏览器通过request上传的文件名不一致,有是完整路径,有点是文件名: c:\a\b\1.txt or
// 1.txt
fileName = fileName
.substring((fileName.lastIndexOf("\\") + 1));
InputStream in = item.getInputStream();
//FileOutputStream out = new FileOutputStream(savePath + "\\"
// + fileName);
//解决上传文件重名问题
String saveName = makeFileName(fileName);
// FileOutputStream out = new FileOutputStream(savePath + "\\"
// +saveName);
//文件打散算法
String realSavePath = makeSavePath(savePath, fileName);
FileOutputStream out = new FileOutputStream(realSavePath + "\\"
+saveName);
byte[] buf = new byte[1024];
int len = 0;
while ((len = in.read(buf)) > 0) {
out.write(buf);
}
out.close();
in.close();
}
}
} catch (FileUploadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
//解决上传文件重名导致文件覆盖问题
private String makeFileName(String fileName){
return UUID.randomUUID()+"_"+fileName;
}
//文件打散问题,解决一个文件下文件过多的问题
private String makeSavePath(String savePath, String fileName){
if(fileName==null || savePath==null){
return null;
}
int hCode = fileName.hashCode();
int dir1 = hCode&0x0f;
int dir2 = (hCode&0xf0)>>4;
String dir = savePath+"\\"+dir1+"\\"+dir2;
//文件要是不存在,创建此文件
File f = new File(dir);
if(!f.exists()){
f.mkdirs();
}
return dir;
}
}
5 上面的示例代码还解决了几个文件上传中的细节问题
5.1 表单名和上传文件名中文乱码问题
解决此问题有两种方法
一:通过request.setCharacterEncoding("UTF-8")来设置中文编码
二:通过ServletFileUpload的setHeaderEncoding方法来设置中文编码
ServletFileUpload upload = new ServletFileUpload(factory);
//方法二:解决上传文件名中文乱码问题
upload.setHeaderEncoding("UTF-8");
5.2 提交的表单内容中文乱码问题
由于设置了form标签的enctype属性值为multipart/form-data,其将通过MIME协议向服务器提交数据,所有表单数据都是通过iso8859-1来编码的。解决此中文乱码问题有两种方法
一:将表单数据通过iso8859-1进行解码,得到源字节码,在通过UTF-8编码
if (item.isFormField()) {
String name = item.getFieldName();
//方法一:数据表单内容的中文乱码问题,按照multipart/form-data上传的数据,都按照iso8859-1进行编码
// 要解决此中文乱码问题,需要先对获取到的数据进行iso8859-1进行解码,在按照UTF-8进行编码
// String value = item.getString();
// value = new String(value.getBytes("iso8859-1"), "UTF-8");
//方法二:解决数据表单内容的中文乱码问题,采用FiltItem类中的getString(Charset)方法,此方法重载了getString
//获取到的数据将按照指定的编码方式进行编码
String value = item.getString("utf-8");
System.out.println(name + ":" + value);
二:通过调用FileItem的getString(Charset charset)来获取表单内容。
5.3 上传文件重名问题
使用UUID方法重写文件名
//解决上传文件重名导致文件覆盖问题
private String makeFileName(String fileName){
return UUID.randomUUID()+"_"+fileName;
}
5.4 上传文件打散问题
使用文件名在内存中的地址(hashcode)来创建存储路径,总共两级目录,第一级目录名为filename 哈希值最低0-4位值,第二级目录名为哈希值低5-8位。
private String makeSavePath(String savePath, String fileName){
if(fileName==null || savePath==null){
return null;
}
int hCode = fileName.hashCode();
int dir1 = hCode&0x0f;
int dir2 = (hCode&0xf0)>>4;
String dir = savePath+"\\"+dir1+"\\"+dir2;
//文件要是不存在,创建此文件
File f = new File(dir);
if(!f.exists()){
f.mkdirs();
}
return dir;
}
相关文章推荐
- struts2文件上传时遇到的几个问题
- 使用HTML的表单form上传文件,需要考虑的几个问题
- 上传文件细节处理问题
- Asp.net 文件上传的 FileUpload FileName 和 FileUpload PostedFile.FileName的细节问题
- [置顶]关于使用input type=file 标签上传文件的注意细节(上传文件 无法获取文件 问题)
- Servlet3.0上传文件时遇到的几个问题
- 上传文件细节处理问题(包括中文乱码、限制文件大小、显示上传速度、删除临时文件,随机生成文件夹等)
- 使用smartupload组件上传文件时的几个问题
- web文件上传中需要考虑的几个问题
- Asp.net 文件上传的 FileUpload FileName 和 FileUpload PostedFile.FileName的细节问题
- 做多文件/图片上传应该注意的几个前后端问题
- 上传文件细节处理问题
- 关于使用input type=file 标签上传文件的注意细节(上传文件 无法获取文件 问题)
- 上传文件细节处理问题
- ASP.net下大文件上传的几个问题讨论
- 上传文件细节处理问题
- 上传文件细节处理问题
- 文件上传的细节问题
- 【PHP】在php文件上传时需要注意的几个细节
- mini2440开发板FTP上传文件的问题