文件的上传和下载在web应用中是非常常用,也是非常有用的功能。

例如:发送电子邮件时可以同过上传附件发送文件,OA系统中可以通过上传文件来提交公文,社交网站通过上传图片来自定义头像等等。

可以说上传和下载是每一个web应用都需要具有的一个功能。

1.先说说文件的上传

1.1 文件上传的步骤

文件的上传主要分成两个步骤:

  1. 用户在页面中选择要上传的文件,然后将请求提交到Servlet。
  2. Servlet收到请求,解析用户上传的文件,然后将文件存储到服务器。
      
1.2 创建上传文件的表单

(1) 创建一个form表单

<form action="" method="post" enctype="multipart/form-data"><input type="file" name="file" /><br /><br /><input type="submit" value="上传" />
</form>

文件上传的表单和之前的表单类似,但有以下内容需要注意:

  • 表单的method属性必须为post
  • 表单的enctype属性必须为multipart/form-data
  • 上传文件的控件是intput,type属性为file

该表单打开后是如下效果:

  • IE

  • Chrome

  • 火狐

(2) 编写Servelet
  页面的表单控件创建好以后,选中文件点击上传按钮请求将会提交到指定的Servlet来处理。
注意:
  这里不能再像以前的Servlet中那样,通过request.getParamter()来获取请求参数了,当enctype=“multipart/form-data” 时,再使用getParamter()获取到内容永远为空。因为浏览器发送请求的方式已经改变。所以要引入一个新的工具commons-fileupload。

  

1.3 commons-fileupload
  • commons-fileupload是Apache开发的一款专门用来处理上传的工具,它的作用就是可以从request对象中解析出,用户发送的请求参数和上传文件的流。
  • commons-fileupload包依赖commons-io,两个包需要同时导入。

核心类:
(1) DiskFileItemFactory

  1. 工厂类,用于创建ServletFileUpload,设置缓存等

  2. 该类一般直接使用构造器直接创建实例

  3. 方法:

    public void setSizeThreshold(int sizeThreshold):用于设置缓存文件的大小(默认值10kb)

    public void setRepository(File repository):用于设置缓存文件位置(默认系统缓存目录)

(2) ServletFileUpload

  1. 该类用于解析request对象从而获取用户发送的请求参数(包括普通参数和文件参数)

  2. 该类需要调用有参构造器创建实例,构造器中需要一个DiskFileItemFactory作为参数

  3. 方法:

    public List parseRequest(HttpServletRequest request):解析request对象,获取请求参数,返回的是一个List,List中保存的是一个FileItem对象,一个对象代表一个请求参数。

    public void setFileSizeMax(long fileSizeMax):设置单个文件的大小限制,单位为B。如果上传文件超出限制,会在parseRequest()抛出异常FileSizeLimitExceededException。

    public void setSizeMax(long sizeMax):限制请求内容的总大小,单位为B。如果上传文件超出限制,会在parseRequest()抛出异常SizeLimitExceededException。

(3) FileItem

  1. 该类用于封装用户发送的参数和文件,也就是用户发送来的信息将会被封装成一个FileItem对象,我们通过该对象获取请求参数或上传文件的信息。

  2. 该类不用我们手动创建,由ServletFileItem解析request后返回。

  3. 方法:

    String getFieldName():获取表单项的名字,也就是input当中的name属性的值。
    String getName():获取上传的文件名,普通的请求参数为null。

    String getString(String encoding):获取内容,encoding参数需要指定一个字符集。

    ​ ① 若为文件,将文件的流转换为字符串。

    ​ ② 若为请求参数,则获取请求参数的value。

    boolean isFormField():判断当前的FileItem封装的是普通请求参数,还是一个文件。

    ​ ① 如果为普通参数返回:true

    ​ ② 如果为文件参数返回:false

    String getContentType():获取上传文件的MIME类型

    long getSize():获取内容的大小

示例代码:

//创建工厂类
DiskFileItemFactory factory = new DiskFileItemFactory();
//创建请求解析器
ServletFileUpload fileUpload = new ServletFileUpload(factory);
//设置上传单个文件的的大小
fileUpload.setFileSizeMax(1024*1024*3);
//设置上传总文件的大小
fileUpload.setSizeMax(1024*1024*3*10);
//设置响应内容的编码
response.setContentType("text/html;charset=utf-8");
try {//解析请求信息,获取FileItem的集合List<FileItem> items = fileUpload.parseRequest(request);//遍历集合for (FileItem fileItem : items) {//如果是普通的表单项if(fileItem.isFormField()){//获取参数名String fieldName = fileItem.getFieldName();//获取参数值String value = fileItem.getString("utf-8");System.out.println(fieldName+" = "+value);//如果是文件表单项}else{//获取文件名String fileName = fileItem.getName();//获取上传路径String realPath = getServletContext().getRealPath("/WEB-INF/upload");//检查upload文件夹是否存在,如果不存在则创建File f = new File(realPath);if(!f.exists()){f.mkdir();};//为避免重名生成一个uuid作为文件名的前缀String prefix = UUID.randomUUID().toString().replace("-", "");//将文件写入到服务器中fileItem.write(new File(realPath+"/"+prefix+"_"+fileName));//清楚文件缓存fileItem.delete();}
}
} catch (Exception e) {if(e instanceof SizeLimitExceededException){//文件总大小超出限制response.getWriter().print("上传文件的总大小不能超过30M");}else if(e instanceof FileSizeLimitExceededException){//单个文件大小超出限制response.getWriter().print("上传单个文件的大小不能超过3M");}
}
response.getWriter().print("上传成功");

  

2.文件的下载

2.1 使用说明

  文件下载最直接的方法就是把文件直接放到服务器的目录中,用户直接访问该文件就可以直接下载。

  但是实际上这种方式并不一定好用,比如我们在服务器上直接放置一个MP3文件,然后通过浏览器访问该文件的地址,如果是IE浏览器可能就会弹出下载窗口,而如果是FireFox和Chrome则有可能直接播放。再有就是有一些文件我们是不希望用户可以直接访问到的,这是我们就要通过Servlet来完成下载功能。

下载文件的关键是几点:
(1) 服务器以一个流的形式将文件发送给浏览器。
(2) 发送流的同时还需要设置几个响应头,来告诉浏览器下载的信息。
具体响应头如下:
Content-Type:

  • 下载文件的MIME类型
  • 可以通过servletContext. getMimeType(String file)获取
  • 也可以直接手动指定
  • 使用response.setContentType(String type);
  • 响应头样式:Content-Type: audio/mpeg

Content-Disposition:

  • 下载文件的名字,主要作用是提供一个默认的用户名
  • 通过response.setHeader(“Content-Disposition”, disposition)设置
  • 响应头样式:Content-Disposition: attachment; filename=xxx.mp3

Content-Length:

  • 下载文件的长度,用于设置文件的长处(不必须)
  • 通过response. setContentLength(int len)设置。
  • 设置后样式:Content-Length: 3140995

(3) 接下来需要以输入流的形式读入硬盘上的文件

  • FileInputStream is = new FileInputStream(file);
  • 这个流就是我们一会要发送给浏览器的内容

(4) 通过response获取一个输出流,并将文件(输入流)通过该流发送给浏览器

  • 获取输出流:ServletOutputStream out = response.getOutputStream();

  • 通过输出流向浏览器发送文件(不要忘了关闭输入流)

    byte[] b = new byte[1024];
    int len = 0;
    while((len=is.read(b))> 0){out.write(b, 0, len);
    }
    is.close();

  

2.2 步骤演示

  • 一下步骤都是在同一个Servlet的doGet()方法中编写的
  • 我所下载的文件是放在WEB-INF下mp3文件夹中的文件

具体步骤:
(1) 获取文件的流:

 String realPath = getServletContext().getRealPath("/WEB-INF/mp3/中国话.mp3");//获取文件的File对象File file = new File(realPath);//获取文件的输入流FileInputStream is = new FileInputStream(file);

(2) 获取头信息:

  //获取文件的MIME信息String contentType = getServletContext().getMimeType(realPath);//设置下载文件的名字String filename = "zhongguohua.mp3";//创建Content-Disposition信息String disposition = "attachment; filename="+ filename ;//获取文件长度long size = file.length();

(3) 设置头信息

//设置Content-Type
response.setContentType(contentType);
//设置Content-Disposition
response.setHeader("Content-Disposition", disposition);
//设置文件长度
response.setContentLength((int)size);

(4) 发送文件

 //通过response获取输出流,用于向浏览器输出内容ServletOutputStream out = response.getOutputStream();//将文件输入流通过输出流输出byte[] b = new byte[1024];int len = 0;while((len=is.read(b))> 0){out.write(b, 0, len);}//最后不要忘记关闭输入流,输出流由Tomcat自己处理,我们不用手动关闭is.close();

  

2.3 乱码

  至此实际上文件下载的主要功能都已经完成。但是还有一个问题我们这里没有体现出来,因为目前我们的文件名使用的是纯英文的,没有乱码问题。这里如果我们要使用中文文件名的话,毫无疑问会出现乱码问题。

解决此问题的方法很简单,在获取文件名之后为文件名进行编码:

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

但是注意这里火狐浏览器比较特殊,因为他默认是以BASE64解码的,所以这块如果需要考虑火狐的问题的话还需要特殊处理一下。

(1) 先要获取客户端信息(通过获取请求头中的User-Agent信息)

//获取客户端信息
String ua = request.getHeader("User-Agent");

(2) 然后判断浏览器版本,做不同的处理(通过判断头信息中是否包含Firefox字符串来判断浏览器版本)

//判断客户端是否为火狐
if(ua.contains("Firefox")){//若为火狐使用BASE64编码filename = "=?utf-8?B?"+new BASE64Encoder()
.encode(filename.getBytes("utf-8"))+"?=";
}else{//否则使用UTF-8filename = URLEncoder.encode(filename,"utf-8");
}

(3)使用String构造方法来选择编码方式。

String string = new String("你好.jpg".getBytes("gbk"), "iso8859-1");

网页上文件的上传和下载相关推荐

  1. 网页 大文件分片上传处理

    总结一下大文件分片上传和断点续传的问题.因为文件过大(比如1G以上),必须要考虑上传过程网络中断的情况.http的网络请求中本身就已经具备了分片上传功能,当传输的文件比较大时,http协议自动会将文件 ...

  2. jsch 移动服务器上文件,jsch上传文件到服务器

    需求就是上传文件到服务器,服务器的存储地址由程序决定然后可以自动创建. 使用第三方:jsch JSch 是SSH2的一个纯Java实现.它允许你连接到一个sshd 服务器,使用端口转发,X11转发,文 ...

  3. 【java】 将服务器上文件夹上所有文件打包并下载

    功能要求:教师端要将学生上传的报告按班级进行打包下载. 前台HTML如下: <td align="right"><button class="layui ...

  4. SpringMVC实现文件的上传和下载

    SpringMVC实现文件的上传和下载http://www.bieryun.com/1120.html 前些天一位江苏经贸的学弟跟我留言问了我这样一个问题:"用什么技术来实现一般网页上文件的 ...

  5. C# 实现FTP文件的上传和下载

    C# 实现FTP文件的上传和下载 任务 任务:在Visual Studio中用C#语言实现对ftp服务器上文件的上传和下载. 现状:初步了解c#语法,对库一无所知 解决:copy别人代码 https: ...

  6. 用WebClinet实现SharePoint上文档库中文件的上传与下载

    微软的SharePoint 提供了强大的文档管理功能,能够创建各种类型的文档库,并对文档进行相应的管理.所以我们的产品也打算将文件用SharePoint来管理,实现文档的共享访问.于是,就产生了用客户 ...

  7. 一篇文章教你学会使用SpringBoot实现文件上传和下载

    文章目录 一.搭建SpringBoot开发环境 1.创建项目 2.配置application.properties参数 3.实体响应类和异常信息类 4.创建FileController 二.接口测试 ...

  8. python selenium 下载文件_Python Selenium —— 文件上传、下载,其实很简单

    很多selenium学习者被浏览器弹出的文件上传.下载框折磨的痛不欲生,今天博主就带你们轻松搞定上传和下载问题. 上传 上传弹框 文件上传是所有UI自动化测试都要面对的一个头疼问题,要处理这个问题,我 ...

  9. java 文件下载 jsp文件_jsp文件 Java实现文件上传与下载

    通过前台选择文件,然后将资源上传到(即新建一个文件)到发布的资源文件下面, 下载就是url 到发布的资源文件,触发即可自动下载.服务器已经封装了如何下载的底层实现.(此处用的是tomcat) JSP上 ...

  10. 云计算学习笔记004---hadoop的简介,以及安装,用命令实现对hdfs系统进行文件的上传下载

    1.Hadoop简介 1.hadoop的诞生 l  Nutch和Lucene之父Doug Cutting在2006年完成Hadoop项目. l  Hadoop并不是一个单词,它来源于DougCutti ...

最新文章

  1. mysql 函数rep_Mysql之各种各样的函数啦
  2. NFS 网络文件系统
  3. KubeCon 改为线上举办 | 云原生生态周报 Vol. 48
  4. 2017北理c语言答案,c语言答案 北理工
  5. 使用.net备份和还原数据库
  6. 遗传算法锦标赛选择java实现_java – 遗传算法锦标赛选择
  7. oracle decode别名,Oracle中decode函数用法 VelHong
  8. 5.0在python中是一个整数常量_python学习之路,基础篇-变量和常量
  9. UG NX 12 草图环境中使用鼠标的说明
  10. ardruino控制继电器_arduino控制继电器
  11. VRP基础介绍:VRP基础
  12. python高精度乘法_洛谷P1919--A*B Problem升级版(NTT优化高精度乘法)
  13. [python复习8] 数据库mysql操作
  14. 【效率工具】markdown文档自动同步到印象笔记evernote
  15. 阿里云物联网平台最完全的使用教程
  16. 九龙证券|AI重塑半导体基础设施,人工智能发展持续加速
  17. 浅析FPGA局部动态可重构技术
  18. 腾讯安全领御为张裕打造高端葡萄酒区块链溯源平台
  19. Android OpenCV (五十九):离散傅里叶变换
  20. 软件开发的管理和控制

热门文章

  1. 2020安洵杯--MISC
  2. 用styler更改样式后,解决数据框中数据无法保留四位小数
  3. 算法---木头切割问题(二分法)
  4. java 调用nc查询引擎_用友NC系统查询引擎应用心得
  5. 计算机磁盘图标显示异常,Win7磁盘图标显示错误是怎么回事?修复分区磁盘图标异常教程...
  6. 2014年总结——回眸过去
  7. 怎样利用计算机打出开方,在电脑上,平方与开方怎么打?
  8. Oracle Comment添加表备注和列备注添加和查询comment on table or culumn
  9. 计算机禁用网络后怎么打开,无线网关,教您笔记本无线网络禁用后怎么开启
  10. js 入门基础(一)