fileUpload

文件上传

文件上传

  • 文件上传的概念:
    • 什么是文件上传,将本地的文件,通过流,写入到服务器上。
  • 文件上传的技术
    • 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("编码方式");获得值
  • 文件上传的原理分析

  • FileUpload文件上传的步骤分析
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    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:磁盘文件项工厂
1
2
3
4
5
//设置缓冲区的大小3M
diskFileItemFactory.setSizeThreshold(3*1024*1024);
//设置临时文件存放的路径(比缓冲区大才会生成临时文件)
String path=this.getServletContext.getRealPath("/temp");
diskFileItemFactory.setRepository(new File(path));
  • ServletFileUpload

    • 判断表单中的enctype属性是否是multipart/form-data

    • 解析 request

    • 设置中文文件名乱码

    • 设置上传的当个文件大小

    • 设置上传的总文件大小

  • FileItem

    • 判断是普通项还是文件上传项

    • 普通项(获得普通项名)

    • 普通项(获得普通项的值)

    • 上传项(获得文件名)

    • 上传项(获得文件输入流)

    • 删除临时文件

文件上传的问题解决

  • 文件名路径重名(老版本的浏览器带文件名路径)

    1
    2
    3
    4
    5
    int id=fileName.lastIndexOf("/");
    if(id!= -1){
       //说明文件名中不包含路径
       fileName=fileName.substring(id+1);
    }
  • 文件名重名(可以封装成一个工具类)

1
2
int idx=fileName.laseIndexOf(".");
String extetion=fileName.substring(idx); String newFileName=UUID.randomUUID().toString().replace("-","")+extetion;
  • 一个目录下存放的文件过多(目录分离)
    • 按时间分离:一个星期一个目录
    • 按用户分离:一个用户一个目录
    • 按个数分离:一个目录下放300个
    • 按算法分离:按照特定的目录分离算法进行分离
1
2
3
4
5
6
7
8
9
//算法分离(工具类中)
//获得唯一文件名的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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//实现文件上传,首先提供这三个属性
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 中呢
  • 有的则需要在拦截器中设置
1
2
3
4
5
6
7
//设置拦截器需要在配置文件中<action>标签中设置
<interceptor-ref name="defaultStack">
    <!-- 数据的最大值 -->
    <param name="fileUpload.maximumSize">1048576</param>
    <!-- 后缀名 -->
    <param name="fileUpload.allows">.jpg</param>
</interceptor-ref>
  • 还需要在配置文件中设置input标签,如果上传内容与拦截器中规定的不同会走Input标签
    • 还能再input返回的页面设置<s:fielderror/>显示上传的错误信息

uploadUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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());
}
}
张冲 wechat
欢迎扫一扫上面的微信关注我,一起交流!
坚持原创技术分享,您的支持将鼓励我继续创,点击打赏!