javaWeb系列之文件上传与下载

一、文件的上传和下载

1、文件上传介绍

1.1什么是文件上传:

   要将客户端(浏览器)大数据存储到服务器端,不将数据直接存储到数据库中,而是要将数据存储到服务器所在的磁盘上,这就要使用文件上传。

1.2为什么使用文件上传

   通过文件上传,可以将浏览器端的大数据直接保存到服务器端。不将数据保存到数据库中,而是保存到服务器磁盘上,这样减少了数据库服务器的压力,对数据的操作更加灵活

2、文件上传的原理分析

2.1概念:

所谓的文件上传就是服务器端通过request对象获取输入流,将浏览器端上传的数据读取出来,保存到服务器端

2.2文件上传的必要前提:

a、提供form表单,method必须是post

bform表单的enctype必须是multipart/form-data

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

2.3enctype属性

作用:告知服务器请求正文的MIME类型。(请求消息头:Content-Type作用是一致的)

可选值:

l application/x-www-form-urlencoded(默认)

正文:name=admin&password=123

服务器获取数据:String name = request.getParameter("name");

l multipart/form-data:

正文:

 

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

文件上传:解析请求正文的每部分的内容。

2.3enctype属性

3、借助第三方的上传组件实现文件上传

3.1fileupload概述

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

导入commons-fileupload相关jar

l commons-fileupload.jar,核心包;

l commons-io.jar,依赖包。

3.2 fileupload的核心类有:

DiskFileItemFactoryServletFileUploadFileItem

 

a、解析原理

 

 

3.3fileupload简单应用

使用fileupload组件的步骤如下:

1. 创建工厂类DiskFileItemFactory对象:

DiskFileItemFactory factory = new DiskFileItemFactory()

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

ServletFileUpload fileUpload = new ServletFileUpload(factory)

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

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

 

 

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();

 

4、文件上传时要考虑的几个问题(经验分享)

a、保证服务器的安全

把保存上传文件的目录放在用户直接访问不到的地方。

 

b、避免文件被覆盖

让文件名唯一即可

 

c、避免同一个文件夹中的文件过多

方案一:按照日期进行打散存储目录

 

方案二:用文件名的hashCode计算打散的存储目录:二级目录

 

 

d、限制文件的大小:web方式不适合上传大的文件

单个文件大小:

ServletFileUpload.setFileSizeMax(字节)

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

ServletFileUpload.setSizeMax(字节)

 

e、上传字段用户没有上传的问题

通过判断文件名是否为空即可

f、临时文件的问题

DiskFileItemFactory:

作用:产生FileItem对象

内部有一个缓存,缓存大小默认是10Kb。如果上传的文件超过10Kb,用磁盘作为缓存。

存放缓存文件的目录在哪里?默认是系统的临时目录。

 

如果自己用IO流实现的文件上传,要在流关闭后,清理临时文件。

FileItem.delete();

5、入门案例

5.1DiskFileItemFactory

     1.设置缓存大小

factory.setSizeThreshold(1024*1024); // 置为1m 默认是10k

     2.设置临时文件存储位置

   File temp=new File(this.getServletContext().getRealPath("/temp"));

   factory.setRepository(temp); //可以指定 临时文件存储位置,默认是系统的临时文件    存储位置     

5.2ServletFileUpload

     1.parseRequest方法

  List<FileItem> pareRequest(HttpServletRequest request)

  得到所有的上传信息,将每一部分映射成FileItem对象

2.isMultipartContent方法

boolean isMultipartContent(HttpServletRequest request)

这个方法返回值是boolean,它是用于判断当前表单是否是一个上传的表单,简单说,就判断它的encType的值是否是 multipart/form-data.

    3.setHeaderEncoding方法

  用于解决上传文件名称中文乱码问题

4.设置上传文件大小

  void setFileSizeMax(long fileSizeMax) 设置单个文件上传大小

  void  setSizeMax(long sizeMax) 设置总文件上传大小

5.3FileItem

   1.isFormField方法

 这个方法返回的是boolean类型,它是判断当前组件是否是上传组件 简单说,就是 判断type="file",如果返回true,代表不是上传组件,返回false,代表是上传组件

2.getName方法

 获取非上传组件的上传文件的名称,如果是非上传组件,返回的是null

3.getFieldName方法

 获取组件名称,简单说,就是表单的元素的name值。

4.getString方法

 获取非上传组件的value

getString()有一个重载的方法 getString(String encoding)可以解决乱码问题

   5.getInputStream方法

通过FileItem.getInputStream();可以获取一个输入流,这个输入流就可以

读取出上传文件内容。

6.delete方法

它是用于上传完成后,删除临时文件的

6、多文件上传

   function addFile() {

//1.得到idcontentdiv

var div=document.getElementById("content");

//2.向其中添加一段html代码

div.innerHTML+="<div><input type='file' name='f'><input type='button' value='remove File' οnclick='removeFile(this);'></div>";

}

function removeFile(btn){

document.getElementById("content").removeChild(btn.parentNode);

}

7、文件上传问题

7.1 文件重命名

1.上传操作文件重名问题分析

每一个客户端都可以进行文件上传操作,那么当我们上传的文件过多,一定会出现同名的文件,那么在服务器端只能保存一个,对于这个问题,我们在上传文件时,就需要考虑文件重名问题

2.上传操作文件重名解决方案

一般情况下,对于上传文件,为了保证不重名,会给文件起一个随机名.

a.一种方案是使用uuid.

b.一种方案是使用毫秒值

 

7.2  存储位置

1.上传操作文件存储位置分析

本质就是上传的文件是否允许浏览器端直接访问。例如:商品添加时需要一个图片,这个图片一定是可以直接被浏览器端访问的。

2.上传操作文件存储位置解决方案

a.允许被浏览器端访问:放置在WebRoot下,但不能是WEB-INFMETA-INF下其及子目录下

b.不允许被浏览器端访问:

工程下:放置在WEB-INFMETA-INF及其子目录下.

不放在工程下

7.3  目录分离

1.上传操作文件过多问题分析

当我们上传文件过多,并且保存在同一个目录下时,我们就需要考虑怎样处理它们,因为一个目录下文件过多,不仅降低性能,操作时也不方便。

2.上传操作文件过多解决方案

为了防止同一个目录下方上传文件数量过多

1) 按照上传时间进行目录分离 (周、月 )

2) 按照上传用户进行目录分离 ----- 为每个用户建立单独目录

3) 按照固定数量进行目录分离 ------ 假设每个目录只能存放3000个文件 ,每当一个目录存满3000个文件后,创建一个新的目录

4).按照唯一文件名的hashcode 进行目录分离

8、文件的下载

8.1  什么是下载

所谓的下载,其实就是将服务器端的资源通过io流写回到浏览器端。

8.2  超链接实现下载

如果文件可以直接被浏览器解析,会直接在浏览器上打开。

如果不能解析,可以下载

通过另存为进行下载

这种下载方式:当路径提交时,会通过缺省的servlet将文件直接写回到浏览器端.  

 

8.3  超链接下载问题分析

不能被浏览器直接访问的文件,不可以使用超连接下载.

原因是在http响应头中content-type,如果它的值可以被浏览器解析,

那么响应回的内容就会被浏览器端直接解析,如果content-type的值,不可以被浏览器直接解析,那么就会下载。

8.4  服务器端编码实现下载

1.服务器端编码下载原理分析

通过response可以获取输出流,我们将要下载的资源,通过response获取的输出流直接写回到浏览器端就可以。

2.服务器端下载两个响应头设置

a.怎样能通知浏览器,下载文件是什么?

通过response.setContentType()正设置响应数据的 mimeType类型.

要想获取一个文件的mimeType类型

ServletContext.getMimeType(String filename);

b.下载时可不可以有个下载的提示框?

response.setHeader("Content- Disposition","attachment;filename=下载文件名");

8.5  关于下载时乱码问题分析与解决

对于下载时,我们在显示下载文件名称时,如果包含了中文,就可能出现乱码问题,出现的原因,是对于不同的浏览器,它们在处理下载文件时的编码不一致,ie浏览器使用的是utf-8编码,而firefox浏览器使用的是base64编码

    if (agent.contains("MSIE")) {

// IE浏览器

filename = URLEncoder.encode(filename, "utf-8");

filename = filename.replace("+", " ");

} else if (agent.contains("Firefox")) {

// 火狐浏览器

BASE64Encoder base64Encoder = new BASE64Encoder();

filename = "=?utf-8?B?"

+ base64Encoder.encode(filename.getBytes("utf-8")) + "?=";

} else {

// 其它浏览器

filename = URLEncoder.encode(filename, "utf-8");

}

简单处理下载乱码问题

其实我们也可以使用下面代码解决下载时乱码问题

response.setHeader( "Content-Disposition", "attachment;filename=" + new String( fileName.getBytes("gb2312"), "ISO8859-1" ) );

 

 

    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值