文件上传
文件上传
- 文件上传的概念:
- 什么是文件上传,将本地的文件,通过流,写入到服务器上。
- 文件上传的技术
- jspSmartUpload:应用在jsp中的文件上传和下载的组建。(应用在Model1年代)
- fileUpload : Apache下的一个子项目,在java的环境下实现文件的上传
- Servlet3.0 : 注解开发,文件上传(API不全 ),异步请求
- struts2 : 支持文件上传(底层FileUpload)
文件上传的要素:
- 表单提交的方式是post(get有大小限制)
- 表单中必须有文件上传项,而且必须要有name属性跟值。
<input type="file" name="upload">
- 表单中必须要有
enctype
属性值为multipart/form-data
要不拿不到文件内容
- enctype有默认值为
application/x-www-form-urlencoded
如果不改的话,上传文件的时候只能上传文件名 enctype
属性值为multipart/form-data
时就不能用getParameter();来获得属性了要用String name =fileItem.getFiledName();
来获得名字,用String value=fileItem.getString("编码方式");
获得值
- enctype有默认值为
文件上传的原理分析
FileUpload文件上传的步骤分析
1.创建一个磁盘文件项工厂
DiskFileItemFactory diskFileItemFactory=new DiskFileItemFactory();
2.创建核心解析类
ServletFileUpload servletFileUpload=new ServletFileUpload(diskFileItemFactory);
3.解析request,返回List集合
List<FileItem> list = servletFileUpload.parseRequest(request);
4.遍历集合获得每个部分的内容,获得每个部分,如果是文件上传项,完成文件上传工作操作。
for(FileItem fileItem:list){
//4.1判断是否是普通项
if(fileItem.isFileField()){
//普通项
//接受到普通项的名字跟值
String name =fileItem.getFiledName();
String value=fileItem.getString();
}else{
//文件项
//获得文件名跟输入流
String fileName=fileItem.getName();
InputStream is=fileItem.getInputStream();
//获得文件上传的路径:
String path =this.getServletContext.getRealPath("/upload");
OutputStream os=new FileOutputStream(path + "/"+fileName);
//两个流对接
int len =0;
byte[] b=new byte[1024];
while((len=is.read(b))!=-1){
os.write(b,0,len);
}
is.close();
os.close();
}
//删除临时文件
fileItem.delete();
}
FileUpload中API
- DiskFileItemFactory:磁盘文件项工厂
//设置缓冲区的大小3M
diskFileItemFactory.setSizeThreshold(3*1024*1024);
//设置临时文件存放的路径(比缓冲区大才会生成临时文件)
String path=this.getServletContext.getRealPath("/temp");
diskFileItemFactory.setRepository(new File(path));
ServletFileUpload
判断表单中的enctype属性是否是multipart/form-data
解析 request
设置中文文件名乱码
设置上传的当个文件大小
- public void setFileSizeMax(long fileSizeMax)
设置上传的总文件大小
- public void setSizeMax(long sizeMax)
FileItem
判断是普通项还是文件上传项
- boolean isFormField()
普通项(获得普通项名)
- String getFieldName()
普通项(获得普通项的值)
- String getString()
String getString(String encoding)
- String getString()
上传项(获得文件名)
- String getName()
上传项(获得文件输入流)
- InputStream getInputStream()
- 删除临时文件
- void delete()
文件上传的问题解决
- 文件名路径重名(老版本的浏览器带文件名路径)
int id=fileName.lastIndexOf("/");
if(id!= -1){
//说明文件名中不包含路径
fileName=fileName.substring(id+1);
}
- 文件名重名(可以封装成一个工具类)
int idx=fileName.laseIndexOf(".");
String extetion=fileName.substring(idx); String newFileName=UUID.randomUUID().toString().replace("-","")+extetion;
- 一个目录下存放的文件过多(目录分离)
- 按时间分离:一个星期一个目录
- 按用户分离:一个用户一个目录
- 按个数分离:一个目录下放300个
- 按算法分离:按照特定的目录分离算法进行分离
//算法分离(工具类中)
//获得唯一文件名的hashcode值
int code1=uuidFileName.hashCode();
//让这个值&0xf 到一个一级目录
int d1=code1 & 0xf;
//让hashcode值右移4位
int code2=code1>>>4;
int d2 = code2 & 0xf; //作为2级目录
return "/"+d1+"/"+d2;
以此类推可以得到最多8级目录,每级中有16个不同的值。
使用这个工具类时如下:
注:
在文件上传的时候因为form表单中的enctype
属性值为mulipart/form-data
时就不能用getParameter()
了,所以就不能继承basicServlet了,要单独自己写一个servlet
Struts中的文件上传
- Struts2中实现文件上传的基本的功能:
- 在Struts2中实现文件上传是通过拦截器实现的
- 提供三个对象的属性即可:
- 上传的文件名:表单上传的名称+FileName.
private String uploadFileName;
- 上传的文件类型:表单上传名称+ContentType.
private String uploadContentType;
- 上传的文件 文件类型的表单上传项。
private Fileupload.
- 上传的文件名:表单上传的名称+FileName.
//实现文件上传,首先提供这三个属性
private String uploadFileName;
private String uploadContentType;
private File upload;
//记得要提供set方法
//在指定的方法中实现文件上传
private String uploadAction(){
//判断是否选中文件
if(upload != null){
//文件上传的路劲
String realPath=".....";
//可以获得唯一文件名
String uuidFileName = UploadUtils.getUUIDFileName(uploadFileName);
//获得目录分离的路劲
String path = UploadUtils.getPath(uuidFileName);
File file = new File (realPath + path);
if(!file.exists()){
file.mkdirs();
}
//创建一个文件目录
String str=readPath+path+"/"+uuidFileName;
File dickFile = new File (str);
//实现文件上传
FileUtils.copyFile(upload,dickFile);
}
return "saveSuccess";
}
- 文件上传的参数都在
default.properties
中呢 - 有的则需要在拦截器中设置
//设置拦截器需要在配置文件中<action>标签中设置
<interceptor-ref name="defaultStack">
<!-- 数据的最大值 -->
<param name="fileUpload.maximumSize">1048576</param>
<!-- 后缀名 -->
<param name="fileUpload.allows">.jpg</param>
</interceptor-ref>
- 还需要在配置文件中设置input标签,如果上传内容与拦截器中规定的不同会走Input标签
- 还能再input返回的页面设置
<s:fielderror/>
显示上传的错误信息
- 还能再input返回的页面设置
uploadUtils
import java.util.UUID;
/**
* 文件上传的工具类
* @author zc
*
*/
public class UploadUtils {
/**
* 获得唯一文件名的方法:
* @param fileName
* @return
*/
public static String getUUIDFileName(String fileName){
// aaa.txt --- sdklflsdf.txt
int idx = fileName.lastIndexOf(".");
String extetion = fileName.substring(idx);
return UUID.randomUUID().toString().replace("-", "")+extetion;
}
/**
* 获得分录分录的路径:
* @param args
*/
public static String getPath(String uuidFileName){
// 获得唯一文件名的hashCode值。
int code1 = uuidFileName.hashCode();
// 让这个值&0xf 得到一个一级目录。
int d1 = code1 & 0xf;// 作为1级目录.
// 让hashCode值右移4位:
int code2 = code1 >>> 4;
int d2 = code2 & 0xf; // 作为2级目录.
return "/"+d1+"/"+d2;
}
public static void main(String[] args) {
System.out.println("986a6146e9104e00838c123bcc371cd3.txt".hashCode());
}
}