/*
*文件上传
*文件上传:将客户端资源通过网络传递到的服务器端
*为什么使用文件上传呢?
*因为数据过大,必须通过文件上传才可以将数据保存到服务器端的操作
*本质:io流操作
*演示文件上传:
*浏览器端:
*method=post,因为只有post才能携带大数据
*必须使用,必须有那么属性
*必须在form标签上添加这个属性:enctype="multipart/form-data"
*服务器端:
*request对象用于获取请求信息
它有一个getInputStream()方法,可以获取一个字节输入流
通过这个流,可以读取到所有的请求正文信息
**文件上传原理:浏览器端注意上述三件事
在服务器端通过流将数据读取到
再对数据进行解析,将文件的内容得到
保存在服务器端就完成了文件上传
*实际开发中不需要我们进行数据解析
因为我们可以利用以及封装好了的工具去操作
即提供API,只要调用就可以了
*commons-fileupload 是Apache提供的开源免费的文件上传工具
*使用
*导包
*commons-fileupload-1.2.1.jar 文件上传
*commons-io-1.4.jar io工具
*commons-fileupload
*三个核心
*DiskFileItemFactory
*ServletFileUpload
*FileItem
*入门:
*创建upload2.jsp页面
*创建Upload2Servlet
*创建一个DiskFileItemFactory
DiskFileItemFactory factory=new DiskFileItemFactory();
*创建ServletFileUpload类
ServletFileUpload upload=new ServletFileUpload(factory);
*解析所有上传数据
List
items = upload.parseRequest(request);
*了遍历items集合,集合中的每一项,就是一个上传数据.
*isFormField();
是否是上传组件
*getFieldName();
返回值String,得到组件名称,即name属性名
*getName();
返回值是String,得到的是上传文件的名称.
注意:浏览器不同,它们得到的效果不一样。
*包含全路径名称 例如: C:\Users\Administrator\Desktop\a.txt
*只包含上传文件名称 例如:a.txt
*getString();
*获取非上传组件的内容,相当于getParameter()的作用
如果是上传组件,上传的文件是文本文件,可以获取到文本文件的内容
如果不是文本文件,比如是张图片,这样获取就不合适
*获取上传文件内容
*用流获取,非文本还不能打印在控制台。
item.getInputStream();它是用于读取上传文件内容的输入流.
所以只能再用流操作,保存到服务端
FileOutputStream fos=new FileOutputStream("文件保存地址");
其余就是读取写入的基本步骤
但是,其实人家的工具底层是完成了的,
IOUtils.copy(item.getInputStream(), fos);
这个工具的方法,只需要提供两个流对象,底层人家是实现了的
具体的实现是不需要我们去做的。
*DiskFileItemFactory
*作用:设置缓存大小以及临时文件保存的位置
*默认缓存大小10240K,临时文件的有无取决于缓存的大小,如果文件太小,内存就可以装下,就用不到缓存了
*临时文件默认存储在系统的临时文件目录下,可以在环境变量中查看
*使用步骤:
*new DiskFileItemFactory():无参构造,就是使用默认缓存大小和临时文件位置
有参构造,则是自己制定那两个值
**this.getServletContext().getRealPath("/temp"):获取temp目录部署到tomcat服务器后的绝对磁盘路径
这个必须会,开发中很常用。
这个temp如果直接在webRoot目录下,就直接这样写,如果在其他目录下,就先写它的父目录
*对于无参构造,也可以设置临时文件存储位置和缓存大小,有对应的方法区设置
*setSizeThreshold(int sizeThreshold)
*setRepositiry(File repositiry)
*ServletFileUpload
*ServletFileUpload upload=new ServletFileUpload();
*创建一个上传工具,指定临时缓存区和临时文件的存储位置
*List
items=upload.parseRequest(request);
*它是用于解析request对象,得到所有上传项.每一个FileItem就相当于一个上传项.
*boolean flag=upload.isMultipartContent(request);
*用于判断是否是上传.
*可以简单理解,就是判断encType="multipart/form-data";
*设置上传文件大小
void setFileSizeMax(long fileSizeMax) 设置单个文件上传大小
void setSizeMax(long sizeMax) 设置总文件上传大小
*解决上传文件中文名称乱码
*setHeaderEncoding("utf-8");
注意:如果使用reqeust.setCharacterEncoding("utf-8")也可以,但不建议使用。
既然在使用工具了,就使用工具的方法去解决。虽然request的方法也没有任何问题。
以后也不建议使用request去获取请求参数了,毕竟人家提供了工具,但是,不是不能使用使用request
毕竟要用request的地方,还是必须要用的。咋感觉怎么拗口呢。。。
*FileItem
*isFormField();
判断是否是上传组件,
如果是
返回false,否则返回true
getFieldName();
返回值String,得到组件名称,即name属性名
*getName();
返回值是String,得到的是上传文件的名称.
注意:浏览器不同,它们得到的效果不一样。
*包含全路径名称 例如: C:\Users\Administrator\Desktop\a.txt
*只包含上传文件名称 例如:a.txt
*getString();
*获取非上传组件的内容,相当于getParameter()的作用
出现中文乱码
*getString("utf-8");
如果是上传组件,上传的文件是文本文件,可以获取到文本文件的内容
如果不是文本文件,比如是张图片,这样获取就不合适
*获取上传文件内容
*用流获取,非文本还不能打印在控制台。
*删除临时文件:
*item.delete();
*乱码问题解决:
*上传文件名称乱码
*ServletFileUpload.setHeaderEncoding("utf-8");
*非上传组件内容乱码
*FileItem.getString("utf-8");
*上传文件内容乱码:
*不需要解决
因为上传时使用的是字节流进行复制的,字节流是不可能出现乱码的
即:如果想需要的信息原样不动的拿过来,就用字节,绝对不会乱
*多文件上传
*服务器端代码不需要改变.
*上传文件注意事项
*上传文件在服务器端保存的位置
*保存在可以被浏览器直接访问的位置:例如淘宝的商品图片
*工程的webRoot目录下的路径(不包含META-INF和WEB-INF目录及其子目录)
*保存在不可以被浏览器直接访问的位置:例如付费资源的访问
*工程中:META-INF和WEB-INF目录及其子目录下
*不在工程中:服务器的磁盘目录下
*上传文件在同一目录下重名
*在开发中,一般会给上传文件起一个随机名
但是为了防止因为名字随机而不好找的问题,真实的开发中会在数据库中添加一个关于真实名字和随机名字的记录
*随机名怎么取
*使用当前毫秒值
*使用UUID
*同一目录下文件过多
*分目录
*按用户 (为每个用户建立单独的目录)
*按上传时间(周,月)
*按固定数量(假设每个目录下存放固定多少个目录)
*按照唯一文件名的hashcode进行目录分离
public static String generateRandomDir(String uuidFileName) {
// 获得唯一文件名的hashcode
int hashcode = uuidFileName.hashCode();
// 获得一级目录
int d1 = hashcode & 0xf;
// 获得二级目录
int d2 = (hashcode >>> 4) & 0xf;
return "/" + d2 + "/" + d1;// 共有256目录l
}//使用移位运算,提高效率,但是,不咋看得懂,移位运算那里,晕晕的
*File file=new File(String path); "d:/a/a.txt"
File file=new File(String parent,String path); "d:/a" "a.txt"
File file=new File(File parent,File file);
File file=new File(File parent,String file);
*文件下载
*方式:
*超链接下载
*download1.jsp
a.bmp
a.doc
a.txt
tk.mp3
*如果这个文件可以直接被浏览器解析,会在浏览器中直接打开,不会下载
如果不能被浏览器解析,就会下载
要想下载直接解析的,只有右键另存为
*超链接下载的条件:要求下载的资源可以直接被浏览器访问的,即存在特定的目录下
*客户端访问服务器静态资源文件时,静态资源文件是通过缺省Servlet返回的,
在tomcat配置文件conf/web.xml 找到 --- org.apache.catalina.servlets.DefaultServlet
*即,如果我们在网上遇到了需要登录才能下载的东西,如果那个东西在浏览器上可以直接看到了,
就直接右键另存为,不用傻乎乎的去登录了。
*服务器端通过编程完成下载
*编写页面download2.jsp
a.bmp
a.doc
a.txt
tk.mp3
*在DownLoadServlet中进行的操作
*得到要下载的文件名称
*String filename = request.getParameter("filename");
*在d:/upload目录下查找这个文件是否存在
*File file = new File("d:/upload/" + filename);
if(file.exists())
*进行下载,通过response获取输出流,将文件内容写会到浏览器端
*FileInputStream fis=new FileInputStream(file);
OutputStream out=response.getOutputStream();
int len=0;
byte [] buf=new byte[1024];
while((len=fis.read(buf))!=-1)
{
out.write(buf,0,len);
out.flush();
}
fis.close();
out.close();
*注意:
*要想通过编程的方式实现文件下载,
*设置mimeType
response.setContentType(String mimeType)
*怎样获取要下载文件的mimeType类型
this.getServletContext.getMimeType("要下载的文件名");
如果设置了mimeType,浏览器能解析的就直接展示,不能解析的,就会提示你是否下载
*设置一个响应头,设置后可以不论返回的是否是可以被浏览器解析,都下载
response.setHeader("content-disposition","attachment;filename=要下载的文件名");
额,就是之前讲响应头的时候,设置以下载的方式打开文件嘛。傻得很,这都忘了
*总结:服务器端编程下载
*将下载的文件通过输出流response.getOutputStream()写回到浏览器端
*设置mimeType response.setContentType(String this.getServletContext.getMimeType("要下载的文件名"))
*设置响应头:response.setHeader("content-disposition","attachment;filename=要下载的文件名");
*乱码问题:不是内容(字节流不会出现乱码),是文件名的乱码问题
*下载时中文名称资源请求不到
*因为资源名称是通过get请求拼接过来的。
*解决:new String(filename.getBytes("iso-8859"),"utf-8");
*下载文件显示时的中文乱码问题
*不同浏览器解决方式不同
response.setHeader("content-disposition","attachment;filename="+filename);
*不同浏览器编码方式不同
MSIE,Chrome:filename utf-8编码
firefox:filename base64编码
*判断浏览器:
String useragent=request.getHeader("user-agent");
获取浏览器类型
*使用队列来优化递归操作
*队列:先进先出
栈:先进后出
*在jdk中有一个接口:Queue 已知实现类LinkedList,其实就是一个队列
如果要使用队列,插入是使用 offer,获取并移除队列的头 poll
Queue queue=new LinkedList();
*使用队列来优化递归操作,可以解决目录层次过多的问题
因为:递归操作可以理解成纵向的遍历,如果目录层次较多,在内存中存储的数据也多,也许会移除
使用队列,它是横向遍历的,一层一层的遍历,可以解决目录层次比较多的问题
使用队列,最多的时候在内存中只存储了一层一层的信息
界面展示的树形结构是递归做的
如果层次较深,就需要用队列了。
*/
笔记--文件上传下载
最新推荐文章于 2025-05-20 19:27:01 发布