javaEE(文件上传和下载)

蹲街弑〆低调 提交于 2019-12-04 15:00:07

文件上传


文件上传的前提

a.提供form表单,method必需是post

b.form表单的enctype必需multipart/form-data

c.提供input type="file"类的上传输入域

enctpe(编码类型)告诉服务器请求类型,与属性Context-type作用一致。


application/x-www-form-urlencoded(默认):默认传递的是表单数据,名字和值

multipart/form-data:请求正文

1.这时候请求正文改变了,成字节流传递!!(其中有表单text和file控件提交的正文xi)

文件上传注意事项

服务器获取数据:request.getParameter(String)方法获取指定的表单字段字符内容,但文件上传表单已经不在是字符内容,而是字节内容,所以失效。

    可以用request.getInputStream()来获取表单提交的字节流信息,然后对字节流信息截取,获取上传文件的信息。

工具类:fileupLoad

fileupload是由apache的commons组件提供的上传组件,它主要工作就是帮我们解析request.getInputStream()。

步骤:

1.导入commons-fileupload.jar(核心包)和commons-io.jar(依赖包),前者解析字节流,后者涉及读写

fileupload核心类

DiskFileItemFactory(磁盘对象,加载后者) ServletFileUpload(核心对对象) FileItem(表单项)

表单项:form提交表单中一个file一个text一个radio都是代表一个表单项,对应一个FileItem类

fileupload简单应用

使用fileupload组件的步骤如下:

1.     创建工厂类DiskFileItemFactory对象:

DiskFileItemFactory factory = new DiskFileItemFactory()

2.     使用工厂创建解析器对象:

ServletFileUpload fileUpload = new ServletFileUpload(factory)

3.     使用解析器来解析request对象:

List<FileItem> list = fileUpload.parseRequest(request)

//判断表单是否支持文件上传
        boolean multipartContent = ServletFileUpload.isMultipartContent(request);
        if(!multipartContent){
            throw new RuntimeException("你的表单不是上传控件");
        }
        //创建DiskFileItemfactory
        DiskFileItemFactory factory=new DiskFileItemFactory();
        //创建一个ServletFileUpload核心对象
        ServletFileUpload upload = new ServletFileUpload(factory);
        try {
            //解析request对象,并得到一个表单项的集合
            List<FileItem> list = upload.parseRequest(request);
            //遍历表单项的数据
            for(FileItem fileItem:list){
                //普通表单
                if(fileItem.isFormField()){
                    String name=fileItem.getFieldName();//字段名
                    fileItem.getString();//获取字段内容,如果是文件字段,那么获取的是文件内容,但是文件必须是文本
                }else{
                    //上传表单项
                    String name=fileItem.getName();//获取文件名
                    InputStream inputStream = fileItem.getInputStream();//得到文件输入流
                    //获取真实路径,及服务器运行时路径
                    String directoryRealPath=this.getServletContext().getRealPath("/upload");
                    System.out.println(directoryRealPath);
                    File storDirectory=new File(directoryRealPath);
                    if(!storDirectory.exists()){
                        //不存在的时候
                        storDirectory.mkdirs();//创建一个指定目录;
                    }
                    File file=new File(storDirectory,name);
                    FileOutputStream out = new FileOutputStream(file);//输出到磁盘
                    int len=0;
                    byte[] b=new byte[1024];
                    while((len=inputStream.read(b))!=-1){
                        out.write(b,0,len);
                    }
                }
            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        }

FileItem对象对应一个表单项(表单字段)。可以是文件字段或普通字段

l  boolean isFormField():判断当前表单字段是否为普通文本字段,如果返回false,说明是文件字段;

l  String getFieldName():获取字段名称,例如:<input type=”text” name=”username”/>,返回的是username;

l  String getString():获取字段的内容,如果是文件字段,那么获取的是文件内容,当然上传的文件必须是文本文件;

l  String getName():获取文件字段的文件名称; (a.txt)

l  String getContentType():获取上传的文件的MIME类型,例如:text/plain。

l  int getSize():获取上传文件的大小;

l  InputStream getInputStream():获取上传文件对应的输入流;

l  void write(File):把上传的文件保存到指定文件中。

l  delete();


文件上传考虑的几个问题

1.非法文件名(带路径的文件名)
解决办法
 //io工具类的一个获取文件后缀名的工具类
                    if(name!=null) {
                    	name=FilenameUtils.getName(name);
                    	System.out.println(name+"  "+FilenameUtils.getBaseName(name));
                    }

2.上传文件知道地址后,被访问(这样做如果上传一个定时关机的jsp然后访问了,服务器就会挂)
解决办法
把目录放在/WEB-INF/upload
3.避免文件被覆盖(上传文件名相同问题)
//解决文件同名的问题(前面加上随机数)
                    name=UUID.randomUUID()+"_"+name;
4.避免同一个文件夹文件过多(一般一天一个文件夹)
	private String makeChildDirectory(File store) {
		SimpleDateFormat sm=new SimpleDateFormat("yyyy-MM-dd");
		String date = sm.format(new Date());
		File file=new File(store,date);
		if(!file.exists()) {
			//创建目录
			file.mkdirs();
		}
		return file.toString();
	}
5.限制文件的大小(web不适合上传大的文件)

单个文件大小:  

ServletFileUpload.setFileSizeMax(字节)

总文件大小:(多文件上传)

ServletFileUpload.setSizeMax(字节)

6.用户没有上传问题
通过判断文件名是否为空即可
7.临时文件问题(内部有一个缓存,缓存大小默认是10Kb。如果上传的文件超过10Kb,用磁盘作为缓存。)

DiskFileItemFactory:

将请求消息实体中的每一个项目封装成单独的DiskFileItem (FileItem接口的实现) 对象的任务由FileItemFactory

接口的默认实现 DiskFileItemFactory 来完成。当上传的文件项目比较小时, 直接保存在内存中(速度比较快),

比较大时,以临时文件的形式,保存在磁盘临时文件夹

(虽然速度慢些,但是内存资源是有限的)。

//以下是代码:必须设置好上传文件的最大阀值	
final long MAX_SIZE = 10 * 1024 * 1024 * 1024;// 设置上传文件最大为 10G 
//必须设置文件上传服务器上的临时目录
// 文件上传参数配置
// 创建一个新的文件上传句柄  
DiskFileItemFactory factory = new DiskFileItemFactory();  
// 设置内存缓冲区,超过后写入临时文件
factory.setSizeThreshold(4096);  
// 设置上传到服务器上文件的临时存放目录 -- 非常重要,防止存放到系统盘造成系统盘空间不足
factory.setRepository(new File("F:\\uploadFileTemp"));
ServletFileUpload upload = new ServletFileUpload(factory);  
upload.setHeaderEncoding("utf-8");  
// 设置总文件的最大上传值
upload.setSizeMax(MAX_SIZE);  // 文件上传上限10G

//上传成功后一定要删除临时目录的临时文件
fileItem.delete(); // 请务必调用,在文件上传结束后,删除临时目录的文件...

最好记录下文件从开始上传到上传结束的时间点,这个对今后文件上传时间的分析很有用

    另外,因为Struts2的上传功能也引入了该包,但是却做了拦截器限制文件的最大上传大小为2M,可以通过修改它的配置文件动态更改上传文件的大小;

而且,Struts会在文件上传成功后,帮你删除掉临时文件。我这里使用的是Spring MVC,需要在上传类中指定最大上传文件大小,(这玩意一般不动

态设置,最大上传文件大小一般是系统的标准,是让使用者遵循滴),而且必须在上传成功后删除临时文件。


8.上传中文乱码问题(上传带中文文件名乱码问题)
upload.setHeaderEncoding("utf-8");

文件下载

response.setHeader("content-disposition","attachment;filename="+filename);//告诉浏览器下载
response.setHeader("content-type","image/jpeg");//告诉浏览器下载类型,
response.setContentType(this.getServletContext().getMimeType(filename));//根据文件名自动获得文件类型
		//设置一个要下载的文件
		String filename = "销售榜单.csv";
		
		//设置文件名的编码
		if(request.getHeader("user-agent").toLowerCase().contains("msie")){
			filename = URLEncoder.encode(filename, "UTF-8");//将不安全的文件名改为UTF-8格式
		}else{
			filename = new String(filename.getBytes("UTF-8"),"iso-8859-1");//火狐浏览器
		}
		//告知浏览器要下载文件
		response.setHeader("content-disposition", "attachment;filename="+filename);
		//response.setHeader("content-type", "image/jpeg");
		response.setContentType(this.getServletContext().getMimeType(filename));//根据文件名自动获得文件类型
		
		response.setCharacterEncoding("UTF-8");//告知服务器使用什么编码
		//创建一个文件输出流
		PrintWriter out = response.getWriter();
		out.write("电视机,20\n");
		out.write("洗衣机,10\n");
		out.write("冰箱,8\n");

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!