文件上传
(一)文件上传的概述
一、什么是文件上传
文件上传:将本地的文件通过流写入到服务器的过程
二、为什么要学习文件上传
实际开发中有很多应用:
QQ空间上传图片
招聘网站上传简历
三、文件上传的技术
JSPSmartUpload:应用在JSP上的文件上传和下载的组件
FileUpload:应用在Java环境上的文件上传的功能
Servlet3.0:提供了文件上传的功能
Struts2:提供了文件上传的功能
四、文件上传的三个要素
1、表单的提交的方式需要是POST(因为GET有大小限制)
2、表单中需要有<input type="file">元素,还需要有name属性和值
3、表单属性必须设置enctype="multipart/form-data"
(二)文件上传的原理分析
一、抓包分析
1、没有设置enctype属性
POST /web06/jsp/upload.jsp HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 23
Cache-Control: max-age=0
Origin: http://localhost:8080
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Referer: http://localhost:8080/web06/jsp/upload.jsp
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=5EC0B8AC2ED01283DEE896BC835C05FB
info=aaa&upload=aaa.txt
*注意:没有文件上传中的文件的具体内容
2、设置enctype属性
POST /web06/jsp/upload.jsp HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------66193578536799190642897124112
Content-Length: 344
Origin: http://localhost:8080
Connection: keep-alive
Referer: http://localhost:8080/web06/jsp/upload.jsp
Cookie: JSESSIONID=00D32978472B2FE2E35796855713EE40; Pycharm-8dbeb98c=1f31b81e-d44c-45f8-95c1-2b06c10aea65
Upgrade-Insecure-Requests: 1
-----------------------------66193578536799190642897124112
Content-Disposition: form-data; name="info"
aaa
-----------------------------66193578536799190642897124112
Content-Disposition: form-data; name="upload"; filename="aaa.txt"
Content-Type: text/plain
hello world!!
-----------------------------66193578536799190642897124112--
二、文件上传的原理分析
手动实现文件上传:
(1)获得分割线
(2)获得请求体的所有内容:request.getInputStream();
(3)利用分割线将获得内容进行分割
(4)判断是普通项还是文件上传项
普通项:获得普通项名称和值
文件上传项:获得文件名称和文件内容,通过流写到服务器上
(三)文件上传的代码实现
一、引入文件上传的相关jar包
二、编写文件上传的页面
三、编写文件上传的Servlet
(四)文件上传的API
一、DiskFileItemFactory:磁盘文件项工厂
1、构造方法:
DiskFileItemFactory()
DiskFileItemFactory(int sizeThreshold, File repository)
sizeThreshold:用来设置文件上传的缓冲区的大小,默认值为10KB
repository:用来设置文件上传过程中所产生的临时文件存放的路径
2、方法:
setRepository(File repository):设置缓冲区的大小
setSizeThreshold(int sizeThreshold):设置临时文件存放的路径
3、API的使用的代码
二、ServletFileUpload:核心解析类
1、构造方法
ServletFileUpload()
ServletFileUpload(FileItemFactory fileItemFactory)
2、方法
isMultipartContent(HttpServletRequest request)
是用来判断表单的enctype属性是否正确
parseRequest(HttpServletRequest request)
解析Request对象,返回一个List集合(每个部分的对象FileItem)
(long fileSizeMax)
用来设置单个文件的大小
setSizeMax(long sizeMax)
用来设置上传的文件的总大小
setHeaderEncoding(String encoding)
用来解决中文文件名上传的乱码的问题
setProgressListener(ProgressListener pListener)
设置监听文件上传的进度
三、FileItem文件项
1、方法
isFormField()
判断表单项是普通项还是文件上传项,如果为true代表是普通项
2、普通项的方法
getFieldName()
用来获得普通项的名称
getString()
用来获取普通项的值
getString(String encoding)
用来获取普通项的值(可解决乱码问题)
3、文件上传项
getName()
获得上传文件的文件名的方法
getInputStream()
获得上传文件的文件内容的方法
getSize()
获得上传文件的文件大小
delete()
删除文件上传过程中的临时文件
(五)JS控制多文件上传
一、案例需求
案例需求描述
二、案例实现
案例代码实现
(六)文件上传兼容浏览器问题及解决
一、问题描述
如果使用IE老版本的浏览器,会出现一个文件名称获取错误的问题,因为老版本IE获取文件名称的时候,会带有路径
二、问题解决
(七)文件上传同一个目录下文件同名的问题及解决
一、问题描述
张三向服务器上传了一个文件aa.txt,内容是Hello World,李四向服务器上传了一个文件aa.txt,内容是Hello Java,后上传的文件将先上传的文件覆盖了
二、问题解决
使用唯一文件名来解决
(八)文件上传同一个目录下存放文件过多的问题及解决
一、问题描述
现在所有的用户都上传文件,如果网站访问量比较大,如果都上传到同一个目录下,此目录下存放的文件太多了,也会对程序有影响(在打开该目录的时候都会很卡,更别说读写了,效率会更低)
二、问题解决
1、目录分离
按时间分离:按月、周、天、小时
按用户分离:按张三、李四
按个数分离:一个目录下存放3000个文件
按目录分离分离算法:按照某种特定算法进行分离
上传一个文件,得到一个唯一的文件名
获取唯一文件名的hashCode值——int类型的值(占8个字节32位)
让hashCode的值& 0xf;——得出的这个值作为一级目录
让hashCode右移4位再 & 0xf;——得出的这个值作为二级目录
依此类推……
2、分析算法:
依此类推:共得到8级目录,每级目录中又会有从0000-1111的16级子目录,我们就能得到16的8次方个,约43亿个目录
3、算法实现