文件上传

文件上传的概述

文件上传:将本地的文件通过流写入到服务器的过程。

实际开发中有很多应用:
QQ空间上传图片。
招聘网站上传简历。

文件上传的技术

文件上传的要素

文件上传的三个要素:

  • 表单的提交的方式需要是POST
  • 表单中需要有 <input type=“file">元素,需要有name属性和值
  • 表单enctype=“multipart/form-data”

POST请求的编码格式

Post请求的两种编码格式:application/x-www-form-urlencoded和multipart/form-data

首先我们需要明白在html中的enctype属性,
enctype:规定了form表单在发送到服务器时候编码方式。他有如下的三个值。

  • ①application/x-www-form-urlencoded。默认的编码方式。但是在用文本的传输和MP3等大型文件的时候,使用这种编码就显得 效率低下。
  • ②multipart/form-data 。 指定传输数据为二进制类型,比如图片、mp3、文件。
  • ③text/plain。纯文体的传输。空格转换为 “+” 加号,但不对特殊字符编码。

post默认application/x-www-form-urlencoded方式提交:只能获取获取文件的名字不能获取文件的内容。

multipart/form-data方式提交:可以获取文件的内容

总结:文件上传必须使用multipart/form-data编码方式提交

文件上传的原理分析

JSP页面:

<body><h1>文件上传</h1><!-- 文件上传三要素:*    表单需要POST提交* 表单中需要文件上传项,必须有name的属性和值* 表单的enctype属性必须是multipart/form-data--><form action="" method="post" enctype="multipart/form-data">文件描述:<input type="text" name="info"><br>文件上传:<input type="file" name="upload"><br><input type="submit" value="提交"></form>
</body>

文件上传的案例

第一步:引入文件上传相关的jar包:

common-io下载

common-fileupload下载



第二部:编写文件上传的页面

<body><h1>文件上传</h1><!-- 文件上传三要素:*    表单需要POST提交* 表单中需要文件上传项,必须有name的属性和值* 表单的enctype属性必须是multipart/form-data--><form action="${ pageContext.request.contextPath }/UploadServlet" method="post" enctype="multipart/form-data">文件描述:<input type="text" name="info"><br>文件上传:<input type="file" name="upload"><br><input type="submit" value="提交"></form>
</body>

第三部:编写文件上传的Servlet
FileItem类的常用方法
解决tomcat每次重启丢失项目文件的问题

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;/*** 文件上传的Servlet*/
@WebServlet("/UploadServlet")
public class UploadServlet extends HttpServlet {private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {try {// 1.创建磁盘文件项工厂DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();// 2.创建一个核心的解析类,将磁盘文件项放入ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);// 3.利用核心类解析Request,解析后得到多个请求部分。返回一个LIst集合,List集合装的是每个请求部分的内容(FileItem文件项)。List<FileItem> list = fileUpload.parseRequest(request);// 4.遍历List集合,会得到代表每个部分的文件项的对象。根据文件项判断是否是文件上传项。for (FileItem item : list) {// 判断这个文件是普通项还是文件上传项if (item.isFormField()) {// 普通项// 接收普通项的值:(接收值不在使用request.getParameter())String name = item.getFieldName();// 获得普通项的名称String value = item.getString("UTF-8");// 获得普通项的值System.out.println(name + "  " + value);} else {// 文件上传项// 获得文件上传项的文件名称String fileName = item.getName();// IE中获得的是绝对路径,所以需要分割int i = fileName.lastIndexOf("//");if (i != -1) {// 使用的是老版本浏览器fileName = fileName.substring(i + 1);}// 获得文件上传项的数据InputStream is = item.getInputStream();// 获得文件上传的路径:磁盘绝对路径String realPath = getServletContext().getRealPath("/upload");// 创建一个输出流,写入到设置的路径中OutputStream os = new FileOutputStream(realPath + "/" + fileName);// 两个流对接int len = 0;byte[] b = new byte[1024];while ((len = is.read(b)) != -1) {os.write(b, 0, len);}// 释放资源os.close();is.close();}}} catch (Exception e) {e.printStackTrace();}}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}

运行结果:

提交后:
控制台

文件夹

文件上传的API

Commons FileUpload 1.4 API文档

DiskFileItemFactory:磁盘文件项工厂

  • 构造方法

    DiskFileltemFactory()

DiskFileltemFactory(int sizeThreshold,File repostory)
sizeThreshold:设置文件上传的缓冲区的大小,默认值为10kb。
repository:设置文件上传过程中产生临时文件存放的路径。
如果在上传文件的过程中文件的大小超过了缓冲区的大小,就会产生临死文件。

  • 方法
    这里重点学习两个方法

setSizeThreshold():设置缓冲区的大小
setRepository() :设置临时文件存放的路径

案例:
写在文件上传的Servlet中

         // 1.1设置缓冲区大小diskFileItemFactory.setSizeThreshold(1024 * 1024 * 3);// 设置缓存区大小为3M// 1.2设置临时文件存放的路径// 获得临时文件存放的路径String temp = getServletContext().getRealPath("/temp");diskFileItemFactory.setRepository(new File(temp));

运行:
在上传后文件大于缓冲区会在temp文件中存放一个临时文件,这个文件也是可以删除的,在后面会学到。

ServletFileUpload:核心解析类

  • 构造方法
    我们使用的是有参的构造方法,将FileItemFactory传递进去
  • 方法

    isMultipartContext:用来判断表单的enctype属性是否正确
    parseRequest:解析Request对象,返回一个List集合(每个部分的对象FileItem)

ServletFileUpload类的方法不多,他的父类FileUploadBase方法比较多:

学习几个比较常用的:
设置单个文件的大小

设置上传文件的总大小

设置中文文件名乱码的问题

设置监听文件上传的进度

FileItem文件项

FileItem类的常用方法
方法:
判断表单项是普通项还是文件上传项,如果为true代表是普通项。

普通项的方法:
获得普通项的名称

获得普通项的值

文件上传项的方法:
用来获得文件名的方法

获得文件内容的方法

获得文件的大小

返回文件的类型,后缀名。

删除文件上传过程中的临时文件

JS控制多文件上传

案例需求分析

每点一次添加就添加一个文件上传的模块,点击上传后一起上传。

案例实现

实现多文件上传只需要利用JS代码即可。
然后上传到Servlet即可

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript">function add() {//获得id为div1的元素var div1Element = document.getElementById("div1");div1Element.innerHTML += "<div><input type='file' name='upload'/><input type='button' value='删除'   οnclick='del(this)'/></div>"}function del(who) {who.parentNode.parentNode.removeChild(who.parentNode);}
</script>
</head>
<body><h1>多文件上传</h1><form action="${ pageContext.request.contextPath }/UploadServlet" method="post" enctype="multipart/form-data"><input type="button" value="添加" onclick="add()"><input type="submit" value="上传" ><div id="div1"></div></form>
</body>
</html>

文件上传兼容浏览器问题及解决

问题描述

如果使用IE老版本的浏览器出现一个文件名称获取错误问题。
IE老版本获取文件名称的时候,会带有路径。

问题解决

将字符串分割即可

 int i = fileName.lastIndexOf("//");if (i != -1) {// 使用的是老版本浏览器fileName = fileName.substring(i + 1);}

文件上传同一个目录下文件同名的问题及解决

问题描述

张三向服务器上传了一个文件aa.txt内容是hello world。李四向服务器上传了一个文件aa.txt内容helloJava。后上传的文件将先上传的文件覆盖了。

问题解决

创建一个工具类:
传递一个文件名,返回一个唯一的文件名

/*** 文件上传的工具类* * @author 25858**/
public class UploadUtils {/*** 传递一个文件名,返回一个唯一的文件名*/public static String getUuidFilename(String fileName) {// 在java的API中有一个类UUID可以产生随机的字符串// UUID.randomUUID().toString();// 获得文件名的扩展名int index = fileName.lastIndexOf(".");String extetions = fileName.substring(index);return UUID.randomUUID().toString() + extetions;}
}

在使用的过程中将文件名传递即可,然后在输出流中使用返回的唯一文件名。

文件上传同一个目录下存放文件过多的问题及解决

问题描述

现在所有的用户都上传文件,如果网站访问量比较大,如果都上传到同一个目录下,在同一个目录下存放的文件太多了,也会对程序有影响(其实打开该目录的时候,都会很卡,更别说读写操作)。

问题解决


分析目录分离算发:

同样将目录分离算发写在工具类中:

 /*** 目录分离的算法实现* 两级目录*/public static String getRealPath(String uuidFileName) {int code1 = uuidFileName.hashCode();int d1 = code1 & 0xf;int code2 = code1 >>> 4;int d2 = code2 & 0xf;return "/" + d1 + "/" + d2;}

在Servlet中使用:
将唯一文件名传递,然后组合成新的目录路径,在输出流中使用新的路径。

                 // 获得文件上传的路径:磁盘绝对路径String realPath = getServletContext().getRealPath("/upload");// 进行目录分离String path = UploadUtils.getRealPath(uuidFileName);String newPath = realPath + path;File file = new File(newPath);// 判断文件是否创建if (!file.exists()) {file.mkdirs();}// 创建一个输出流,写入到设置的路径中FileOutputStream os = new FileOutputStream(newPath + "/" + uuidFileName);

文件下载

文件下载的概述

文件下载:将服务器上的个文件,通过流写入到客户端上。

文件下载的方式

超链接方式下载

超链接方式直接写文件的绝对路径即可

<body><h1>文件下载:超链接的方式</h1><a href="${ pageContext.request.contextPath }/download/111.jpg">111.jpg</a><a href="${ pageContext.request.contextPath }/download/aaa.zip">aaa.zip</a>
</body>

如果浏览器支持这个格式的文件就会直接打开,如果浏览器不支持这个格式的文件才会提示下载。

手动编码方式下载

编写文件下载的页面:

 <h1>文件下载:手动编码的方式</h1><a href="${ pageContext.request.contextPath }/DownloadServlet?filename=111.jpg">111.jpg</a><a href="${ pageContext.request.contextPath }/DownloadServlet?filename=aaa.zip">aaa.zip</a>

文件下载的Servlet:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** 文件下载的Servlet*/
@WebServlet("/DownloadServlet")
public class DownloadServlet extends HttpServlet {private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 1.接收参数String filename = request.getParameter("filename");// 2.下载:设置两个头和一个流// 设置Context-Type// 获得文件内容类型String type = getServletContext().getMimeType(filename);// 设置发送到客户端的响应时的内容类型response.setContentType(type);// 设置Content-Disposition// 让浏览器收到这份资源的时候, 以下载的方式提醒用户,而不是直接展示。response.setHeader("Content-Disposition", "attachment;filename=" + filename);// 设置一个代表了文件的输入流String path = getServletContext().getRealPath("/download");InputStream is = new FileInputStream(path + "/" + filename);// 使用response获取输出流OutputStream os = response.getOutputStream();// 两个流对接int len = 0;byte[] b = new byte[1024];while ((len = is.read(b)) != -1) {os.write(b, 0, len);}os.close();is.close();}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}

中文文件的下载

创建一个转换中文名称的工具类:
因为中文在提示下载时是显示不出来的,所以要转换一下。
使用时需要将文件名称和HttpServletRequest 传入其中

mport java.io.UnsupportedEncodingException;
import java.net.URLEncoder;import javax.servlet.http.HttpServletRequest;import sun.misc.BASE64Encoder;/*** 转换中文名称的类* * @author 25858**/
public class DownUtils {public static String filenameEncoding(String filename, HttpServletRequest request)throws UnsupportedEncodingException {// 获得请求头中的User-AgentString agent = request.getHeader("User-Agent");// 根据不同的客户端进行不同的编码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");}return filename;}
}

Servlet类:
在Servlet中使用要注意,将判断浏览器放在获得文件内容类型的下面,还要将输入流中的路径单独创建,因为路径使用的是获取到的正常值,而不是转换后的值。

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import com.wxw.utils.DownUtils;/*** 文件下载的Servlet*/
@WebServlet("/DownloadServlet")
public class DownloadServlet extends HttpServlet {private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 1.接收参数String filename = request.getParameter("filename");// 2.下载:设置两个头和一个流// 设置Context-Type// 获得文件内容类型String type = getServletContext().getMimeType(filename);// 定义一个代表该文件的路径String path = getServletContext().getRealPath("/download");File file = new File(path + "/" + filename);// 判断浏览器并转换中文名称filename = DownUtils.filenameEncoding(filename, request);System.out.println(filename);// 设置发送到客户端的响应时的内容类型response.setContentType(type);// 设置Content-Disposition// 让浏览器收到这份资源的时候, 以下载的方式提醒用户,而不是直接展示。response.setHeader("Content-Disposition", "attachment;filename=" + filename);// 设置一个代表了文件的输入流InputStream is = new FileInputStream(file);// 使用response获取输出流OutputStream os = response.getOutputStream();// 两个流对接int len = 0;byte[] b = new byte[1024];while ((len = is.read(b)) != -1) {os.write(b, 0, len);}os.close();is.close();}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}

案例:给定目录下的文件下载

案例需求

给定一个目录(这个目录可以是任意盘符下的任意路径-这个路径下有多少级目录,每级目录中有多少个文件都是未知的)。
将这个路径中的文件显示到页面上,在页面上给每个问题件都提供响应下载的链接,当点击这个链接的时候,对该文件进行下载。

案例分析

树形数据的遍历和过滤

获取节点的方式:

文件列表显示功能

Java队列(Queue)了解及使用
深入理解FIFO(包含有FIFO深度的解释)

<body><h1>树形遍历</h1><%// 1.创建一个队列Queue<File> queue = new LinkedList<File>();// 2.将根节点入队File root = new File("D:\\壁纸\\壁纸02\\动漫");queue.offer(root);//判断这个队列是否为空,不为空需要遍历while (!queue.isEmpty()) {//将根节点出队File file = queue.poll();//获得更节点下的所有子节点File[] files = file.listFiles();//遍历所以子节点for (File f : files) {//判断此节点是否为叶子节点if (f.isFile()) {%><h4><a href="#"> <%=f.getName()%></a></h4><%} else {queue.offer(f);}}}%>
</body>

下载代码实现

/*** 树形文件下载的代码实现*/
@WebServlet("/DownloadListServlet")
public class DownloadListServlet extends HttpServlet {private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 1.接收参数String path = request.getParameter("filename");File file = new File(path);// 2.下载:设置两个头和一个流// 设置Context-Type// 获得文件内容类型String filename = file.getName();String type = getServletContext().getMimeType(filename);// 设置发送到客户端的响应时的内容类型response.setContentType(type);// 判断浏览器filename = DownUtils.filenameEncoding(filename, request);System.out.println(filename);// 设置Content-Disposition// 让浏览器收到这份资源的时候, 以下载的方式提醒用户,而不是直接展示。response.setHeader("Content-Disposition", "attachment;filename=" + filename);// 设置一个代表了文件的输入流InputStream is = new FileInputStream(file);// 使用response获取输出流OutputStream os = response.getOutputStream();// 两个流对接int len = 0;byte[] b = new byte[1024];while ((len = is.read(b)) != -1) {os.write(b, 0, len);}os.close();is.close();}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}

JavaWeb(12)之文件的上传和下载相关推荐

  1. 手把手教你学javaweb(五)文件的上传和下载

    javaweb项目文件的上传和下载 ​ 在进行文件的上传和下载之前,我们先把javaweb项目做一点点的改动,那就是将LoginServlet的跳转由原来的forward方式改为 redirect方式 ...

  2. JavaWeb 文件的上传和下载

    JavaWeb 文件的上传和下载 这是一个简单的案例,让你快速了解JavaWeb中文件的上传和下载 文件的上传和下载是Web开发中非常常见和重要的功能,很多系统中都会经常使用文件的上传和下载. 如:博 ...

  3. Akka实战:HTTP大文件断点上传、下载,秒传

    2019独角兽企业重金招聘Python工程师标准>>> 访问:https://github.com/yangbajing/scala-applications/tree/master ...

  4. jsp+servlet实现文件的上传和下载

    实现文件的上传和下载首先需要理解几个知识,这样才可以很好的完成文件的上传和下载: (1):上传文件是上传到服务器上,而保存到数据库是文件名 (2):上传文件是以文件转换为二进制流的形式上传的 (3): ...

  5. java struts2下载文件_Struts2下多文件的上传与下载

    Struts2下多文件的上传与下载 目录 多文件 上传 下载 随意文件java Struts2单例 配置 动态读取 李顺利 在网络上,对于Java处理文件上传和下载的技术比较多,而Struts作为一款 ...

  6. Xshell在Windows和Linux间文件的上传和下载

    Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/cou ...

  7. 多类型文件的上传和下载

    由于最近在做一个团队项目<办公OA管理系统>,我负责做公共事务,人事管理两大模块,今天做到一个页面要有一个上传和下载文件的功能,功能很简单,就是文件的上传和下载而已,这里只是分享一下过程, ...

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

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

  9. 初学Java Web(7)——文件的上传和下载

    文件上传 文件上传前的准备 在表单中必须有一个上传的控件 <input type="file" name="testImg"/> 因为 GET 方式 ...

  10. SpringMVC实现文件的上传与下载

    文件的上传与下载可以说是工作中经常使用的功能,现在整理一下,希望能够给大家一个参考.这里以 Maven 的形式来创建项目,相关的配置文件会把主要的内容列出来,其他头文件信息不再一一全部的列出.最后会把 ...

最新文章

  1. 你哪来这么多事(三):学生信息删除
  2. Vue2.0---webpack打包知识点-2
  3. 走近云计算:解密IaaS、PaaS和SaaS
  4. 【转】排序算法复习(Java实现)(一): 插入,冒泡,选择,Shell,快速排序...
  5. Java编程思想 学习笔记7
  6. Jmeter + Grafana + InfluxDB 性能测试监控
  7. Hyperledger Fabric 核心模块(4)orderer 共识
  8. 50个jQuery插件可将你的网站带到另一个高度
  9. COM编程之二 接口
  10. Angular应用里input字段后面的_ngcontent-hqi是什么含义
  11. 在带有组合框的值列表的下拉列表中显示显示属性的子集
  12. 3.0 C++远征:is a
  13. ubuntu 18.04下安装Java
  14. ExtJS中listener方法和handler方法的区别
  15. java anonymous class_java declare anonymous class using proxy api
  16. 我有一个梦想(I have a dream)
  17. 教小师妹学多线程,看完我写的例子,脸红成那样!
  18. DELETE_FAILED_INTERNAL_ERROR 小米之殇
  19. 继小米机器狗、特斯拉机器人后,小鹏汽车发布智能机器马:真的能骑!
  20. 怎样提高计算机内存,怎样增加电脑虚拟内存

热门文章

  1. php基础知识点及留言板功能实现
  2. 百度超级链AI系列创世藏品发售!
  3. Mybatis 不等号的表示方法,if……else
  4. 回收站的东西删了怎么恢复?永久删除的文件如何恢复
  5. (原創) 如何解決ThinkVantage Power Manager『電源配置』無故消失的bug (NB) (ThinkPad) ?...
  6. android togglebutton 自定义,Android 自定义ToggleButton
  7. mysql反引号作用
  8. 桶装水价格表 it 计算机,桶装水配送价格价格如何计算?「大力水手」
  9. 几款好用又不贵的BI工具值得推荐
  10. 给你的宠物做个玩具吧