JavaWeb 文件的上传、下载
文件上传
表单
<form action="HandlerServlet" method="post" enctype="multipart/form-data">
请选择要上传的文件:<input type="file" name="uploadFile" accept="*/*" multiple /><br />
<button type="submit">上传</button>
</form>
指定<form>的method="post", enctype="multipart/form-data"。
accept指定文件类型,有多种类型时逗号分隔,multiple指定可以选择多个文件。
传统处理方式
ServletInputStream inputStream = request.getInputStream();
选择的文件是放在请求消息体中的。获取的输入流中包含了上传的所有文件,如果单个上传还好处理,如果同时上传多个,不好从中分离出单个文件的数据,且自己写代码获取文件名很麻烦。
Commons-FileUpload
Commons-FileUpload是Apache的开源组件,提供了一套处理上传文件的API。
使用FileUpload需要2个jar包:
- commons-fileupload.jar
- commons-io.jar 这是FileUpload依赖的IO包,要单独下载添加。
FileUpload组件主要的接口、类:
- DiskFileItemFactory类 将请求消息实体中的每一个参数都封装为单独的FileItem对象
- ServletFileUpload类 调用DiskFileItemFactory类来封装请求参数,并对封装好的FileItem做进一步处理,以List<FileItem>形式返回
- FileItem接口 用于封装请求参数,提供了一系列操作上传文件的方法。
DiskFileItemFactory类的常用方法
- DiskFileItemFactory() //空参的构造方法,使用默认临界值、系统临时文件夹
- DisFileItemfactory(int size, File repository) //带参的构造方法,指定临界值、缓存目录
- FileItem createItem() //将一个请求参数封装为FileItem,并返回封装好的FileItem。这个方法由DiskFileItemFactory内部自动调用。不用我们管。
- set|SizeThreshold(int size) //设置临界值
- setRepository(File repository) //设置缓存目录。这2个方法都要对应的get方法。
JVM的内存是有限的,比如用户上传一个1G的文件,直接保存在JVM内存中,实打实地占用服务器内存,这绝对不行。
临界值指定文件大小,小于临界值的文件直接存储在JVM内存中,大于临界值的文件,以临时文件(.tmp)的形式保存在缓存目录中。默认为10240,默认单位Byte,即10KB。
缓存目录可以指定为磁盘上的某一个文件夹,以File形式指定,不指定时默认使用系统的临时文件夹。
ServletFileUpload类的常用方法
- ServletFileUpload() //空参构造器
- ServletFileUpload(FileItemFactory fileItemFactory) //带参的构造器,指定使用的FileItemFactory对象。FileItemFactory是接口,一般使用它的实现类DiskFileItemFactory(上面那个类)。
- setFileItemFactory(FileItemFactory fileItemFactory)
- setSizeMax(long size) //设置请求消息实体内容(传递的所有请求参数)的最大尺寸,防止用户恶意上传超大文件浪费服务器存储空间。默认单位Byte。
- setFileSizeMax(long size) //设置单个文件的最大尺寸
- setHeaderEncoding("utf-8") //设置请求参数的字符集,未设置时使用HttpServletRequest设置的字符集,若HttpServletRequest也未设置字符集,则使用系统默认的字符集。
以上几个setter()方法均有对应的getter()方法。
- List<FileItem> parseRequest(HttpServletRequest request) //调用FileItemFactory对象的方法,开始封装每个请求参数,以List<FileItem>形式返回封装好的所有的请求参数
- FileItemIterator getItemIterator(HttpServletRequest request) //同上,只是返回的是迭代器
注意:是封装每一个请求参数,不是只封装上传的文件,所以有些FileItem保存的是普通的请求字段。
FileItem接口常用的方法
- boolean isFormField() //判断这个FileItem封装的是不是普通的表单字段
- String getFieldName() //获取字段名,即表单控件的name属性
- String getName() //获取上传文件的文件名(带有后缀,比如:1.jpg),如果封装的是普通的表单字段,得到是null
- long getSize() //获取文件的大小,默认单位字节
- String getContentType() //获取文件类型,比如image/jpeg
- boolean isInMemory() //是否存储在JVM内存中。如果存储在内存中,返回true;存储在缓存目录中,返回false。
- void write(File file) //将上传文件写到服务器的磁盘中。如果此文件是存储在缓存目录中的,写完会自动删除缓存目录中对应的临时文件。
- InputStream getInputStream() //获取输入流
- void delete() //清除FileItem存储的主体内容,如果存储在缓存目录中,会删除缓存目录中对应的临时文件。虽然GC会自动清除不再使用的临时文件,但使用完立即删除是最好的。
Servlet处理上传文件示例
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
//创建FileItemFactory对象
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
File tempFolder=new File("E:/tempFolder"); //Java中的File即指文件,又指文件夹
if (!tempFolder.exists()){ //不存在就新建
tempFolder.mkdir();
}
//指定缓存目录
diskFileItemFactory.setRepository(tempFolder);
//创建ServletFileUpload对象
ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
//指定编码字符集
servletFileUpload.setHeaderEncoding("utf-8");
try {
//获取List<FileItem>
List<FileItem> fileItems = servletFileUpload.parseRequest(request);
for (FileItem fileItem:fileItems){
if(!fileItem.isFormField()){ //是上传文件
//使用UUID创建唯一的文件名
String fileName= UUID.randomUUID().toString()+"_"+fileItem.getName();
String path="C:/Users/chy/Desktop/upload/"+fileName;
fileItem.write(new File(path)); //写到服务器磁盘上。写完会自动删除临时文件。
}
}
} catch (FileUploadException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
防止文件重名,有2种方式
- 在文件名中加时间戳(毫秒)。当并发量很大时,依然可能出现重名。
- 在文件名中加UUID.randomUUID().toString() 。
UUID即通用唯一识别码,能唯一标识某个东西。
UUID产生的这个字符串包含32个十六进制数,用4根连词线-分为5段,示例: bd95572b-7fcf-46b2-ae3e-6087d66db40f ,8-4-4-4-12的形式。
文件下载
最简单的方式:使用<a>标签直接链接到文件地址。
<a href="http://www.xxx.com/resource/特斯拉.mp4">下载xxx</a>
有2个问题:
- 某些类型的文件,比如jpg、mp3、mp4、txt等会直接在网页中打开、播放,而非下载。
- 如果以后资源地址换了,比如换ftp服务器了、改资源路径了,需要一个个地修改<a>连接的href属性,十分麻烦。
解决方式:
(1)链接到Servlet,并传递文件名。
<a href="downloadServlet?fileName=特斯拉.mp4">下载xxx</a>
(2)Servlet
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
String fileName = request.getParameter("fileName");
//对文件名进行iso8859-1编码
String browerFileName=new String(fileName.getBytes("utf-8"),"iso8859-1");
//指定浏览器行为为下载
response.addHeader("Content-Type","application/octet-stream");
//指定下载文件名。注意这两个都是addHeader(),不是setHeader()
response.addHeader("Content-Disposition","attachment;filename="+browerFileName);
InputStream is = getServletContext().getResourceAsStream("resource/"+fileName); //换路径时只需修改此句中的路径,不用修改每个<a>
ServletOutputStream os= response.getOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len=is.read(buffer))!= -1){ //注意是-1,不是0
os.write(buffer);
}
}
红字是为了解决下载文件名中文乱码。
因为我们使用的是utf-8字符集,而chrome这些浏览器默认使用 iso8859-1 字符集。要转换一下,这样浏览器在设置下载文件名时才能识别文件名中的中文。
其实 <a href="downloadServlet?fileName=特斯拉.mp4">下载xxx</a> ,url中的中文也要转换一下,一个中文字符转换为%xxxx的形式(%后面跟着4个十六进制数)。
<a href="downloadServlet?fileName=<%=URLEncoder.encode("特斯拉.mp4","utf-8")%>">下载</a>
String URLEncoder.encode(String str, String charset) //静态方法,返回编码后的字符串
当然,不转换也行,都能正确识别。
JavaWeb 文件的上传、下载的更多相关文章
- Javaweb学习笔记——上传下载文件
一.前言 在Javaweb中,上传下载是经常用到的功能,对于文件上传,浏览器在上传的过程中是以流的过程将文件传给服务器,一般都是使用commons-fileupload这个包实现上传功能,因为comm ...
- JAVAWEB之文件的上传下载
文件上传下载 文件上传: 本篇文章使用的文件上传的例子使用的都是原生技术,servelt+jdbc+fileupload插件,这也是笔者的习惯,当接触到某些从未接触过的东西时,总是喜欢用最原始的东西将 ...
- 在Window的IIS中创建FTP的Site并用C#进行文件的上传下载
文件传输协议 (FTP) 是一个标准协议,可用来通过 Internet 将文件从一台计算机移到另一台计算机. 这些文件存储在运行 FTP 服务器软件的服务器计算机上. 然后,远程计算机可以使用 FTP ...
- 创建FTP的Site并用C#进行文件的上传下载
创建FTP的Site并用C#进行文件的上传下载 文件传输协议 (FTP) 是一个标准协议,可用来通过 Internet 将文件从一台计算机移到另一台计算机. 这些文件存储在运行 FTP 服务器软件的服 ...
- linux链接及文件互相上传下载
若排版紊乱可查看我的个人博客原文地址 基本操作 本篇博客主要介绍如何去链接远程的linux主机及如何实现本地与远程主机之间文件的上传下载操作,下面的linux系统是CentOS6.6 链接远程linu ...
- Spring实现文件的上传下载
背景:之前一直做的是数据库的增删改查工作,对于文件的上传下载比较排斥,今天研究了下具体的实现,发现其实是很简单.此处不仅要实现单文件的上传,还要实现多文件的上传. 单文件的下载知道了,多文件的下载呢? ...
- SocketIo+SpringMvc实现文件的上传下载
SocketIo+SpringMvc实现文件的上传下载 socketIo不仅可以用来做聊天工具,也可以实现局域网(当然你如果有外网也可用外网)内实现文件的上传和下载,下面是代码的效果演示: GIT地址 ...
- SSM框架之中如何进行文件的上传下载
SSM框架的整合请看我之前的博客:http://www.cnblogs.com/1314wamm/p/6834266.html 现在我们先看如何编写文件的上传下载:你先看你的pom.xml中是否有文件 ...
- python使用ftplib模块实现FTP文件的上传下载
python已经默认安装了ftplib模块,用其中的FTP类可以实现FTP文件的上传下载 FTP文件上传下载 # coding:utf8 from ftplib import FTP def uplo ...
- php文件夹上传下载控件分享
用过浏览器的开发人员都对大文件上传与下载比较困扰,之前遇到了一个php文件夹上传下载的问题,无奈之下自己开发了一套文件上传控件,在这里分享一下.希望能对你有所帮助. 以下是实例的部分脚本文件 这里我先 ...
随机推荐
- day37_8_21表的查询
一.语法 表的查询一般使用select关键字,配合where筛选.顺序如下: # 先后顺序 from where select 二.where约束条件 首先先建立表: create table emp ...
- Mysql基础知识--概述和索引
一.Mysql概述 MySQL原来隶属于MySQL公司,总部位于瑞典 2008.1.16MySQL被SUN公司收购 2009年SUN公司被Oracle公司收购 常见的软件版本 GA(general A ...
- MyBatis 使用 foreach 批量插入
MyBatis 使用 foreach 批量插入 参考博文 老司机学习MyBatis之动态SQL使用foreach在MySQL中批量插入 使用MyBatis一次性插入多条数据时候可以使用 <for ...
- bcc 基于bpf 分析linux 系统性能的强大工具包
bcc 是一个基于bpf 的强大linux io,网络监控分析工具集(当然也可以分析java,ruby,python...) 一张工具图 说明 bcc 好多工具是需要kernel 4.1 的,但是大部 ...
- Flask-SQLAlchemy相关与Flask-Migrate相关
数据库按照一定规则保存应用数据,应用再发起查询,取回所需的数据.Web应用最常使用基于关系模型的数据库,这种数据库也称为SQL数据库,因为它们使用结构化查询语言SQL.不过近年来文档数据库和键 ...
- [LeetCode] 78. Subsets 子集合
Given a set of distinct integers, S, return all possible subsets. Note: Elements in a subset must be ...
- 本地搭建WordPress (XAMPP环境)
1,XAMPP是一个流行的PHP开发环境,官网下载: https://www.apachefriends.org/zh_cn/index.html 然后安装. 官方介绍:XAMPP是最流行的PHP开发 ...
- Intellij IDEA通过Plugins导入vue.js
最近再写vue.js的程序,刚开始使用Intellij IDEA没有导入插件,结果所有vue文件都是文本方式显示,无法使用开发工具的辅助功能,导入vue.js插件后即可. 路径是Setting-> ...
- 深入学习 esp8266 wifimanager源码解析(打造专属自己的web配网)
QQ技术互动交流群:ESP8266&32 物联网开发 群号622368884,不喜勿喷 单片机菜鸟博哥CSDN 1.前言 废话少说,本篇博文的目的就是深入学习 WifiManager 这个gi ...
- SpringBoot+EventBus使用教程(一)
一.简介 EventBus是一个基于发布订阅的事件总线,在Java和Android里都可以使用. 二.使用 1.引入pom <dependency> <groupId>org. ...