目录

文件上传

文件上传的技术

文件上传的要素

文件上传的原理

文件上传的入门案例

文件上传的API

DiskFileItemFactory:磁盘文件项工厂

ServletFileUpload:核心解析类

FileItem文件

JS控制多文件上传

文件上传兼容浏览器问题

文件上传同一个目录下文件同名问题

文件上传同一个目录下文件过多的问题

文件下载

文件下载的方式

中文文件的下载

给定目录下的文件下载


  • 文件上传

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

  1. JSPSmartUpload       :应用在JSP上的文件上传和下载的组件。
  2. FileUpload                  :应用在Java环境上的文件上传的功能。
  3. Servlet3.0                   :提供文件上传的功能
  4. Struts2                        :提供文件上传的功能
  • 文件上传的要素

  1. 文件上传的三个要素
    1. 表单的提交的方式需要是POST
    2. 表单中需要有<input type=”file”>元素,需要有name属性和值。
    3. 表单enctype=”multipart/form-data”
  • 文件上传的原理

  • 抓包分析
  1. 没有设置enctype属性
POST /web06/jsp/upload.jsp HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
X-HttpWatch-RID: 22006-10011
Referer: http://localhost:8080/web06/jsp/upload.jsp
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: localhost:8080
Content-Length: 53
DNT: 1
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: JSESSIONID=D51DCB996556C94861B2C72C4D978010

info=info&upload=C%3A%5CUsers%5Cjt%5CDesktop%5Caa.txt

注意:没有文件上传中的文件的具体的内容。

  1. 设置enctype属性
POST /web06/jsp/upload.jsp HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
X-HttpWatch-RID: 22006-10026
Referer: http://localhost:8080/web06/jsp/upload.jsp
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Content-Type: multipart/form-data; boundary=---------------------------7e139d10110a64
Accept-Encoding: gzip, deflate
Host: localhost:8080
Content-Length: 322
DNT: 1
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: JSESSIONID=D51DCB996556C94861B2C72C4D978010

-----------------------------7e139d10110a64
Content-Disposition: form-data; name="info"

aaa
-----------------------------7e139d10110a64
Content-Disposition: form-data; name="upload"; filename="C:\Users\jt\Desktop\aa.txt"
Content-Type: text/plain

hello world!!!
-----------------------------7e139d10110a64--

 

  • 文件上传的入门案例

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

  • 上传的页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>文件上传</h3>
<!-- 文件上传三要素
		* 表单需要是post提交
		* 表单中需要文件上传项,必须有name的属性和值
		* 表单的enctype属性必须是multipart/form-data
 -->
<form action="${ pageContext.request.contextPath }/UploadFile" method="post" enctype="multipart/form-data">
文件描述:<input type="text" name="info" width="128" height="128"><br/>
上传文件:<input type="file" name="upload"><br/>
<input type="submit" value="上传"/>
</form>
</body>
</html>

 上传代码

package com.toroidals.uploadfile;

import java.io.File;
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.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

/**
 * 上传文件
 */
public class UploadFile extends HttpServlet {

	protected 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 fileItem : list) {
				// 判断这个文件项是否是普通项还是文件上传项。
				if (fileItem.isFormField()) {
					// 普通项:
					// 接收普通项的值:(接收值不能再使用request.getParameter())
					String name = fileItem.getFieldName();// 获得普通项的名称
					// 获得普通项的值
					String value = fileItem.getString("UTF-8");
					System.out.println(name + "    " + value);
				} else {
					// 文件上传项:
					// 获得文件上传项的文件的名称:
					String filename = new File(fileItem.getName()).getName();
					//获得上传文件的输入流
					InputStream inputStream = fileItem.getInputStream();
				    //获得服务器的绝对路径
					String realPath = this.getServletContext().getRealPath("/file");
					String filePath = realPath + "\\" + filename;
					System.out.println(filePath);
					//创建一个输出流,写入到指定路径
					OutputStream outputStream = new FileOutputStream(filePath);
					//传输数据
					int len;
					byte[] bytes = new byte[8192];
					while((len = inputStream.read(bytes)) != -1) {
						outputStream.write(bytes, 0, len);
					}
					inputStream.close();
					outputStream.close();
					System.out.println("文件上传成功");
				}		
			}
		} catch (FileUploadException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}

  • 文件上传的API

  • DiskFileItemFactory:磁盘文件项工厂

  1. 构造方法:

    1. DiskFileItemFactory()
    2. DiskFileItemFactory(int sizeThreshold,File repostory)
      1. sizeThreshold            :设置文件上传的缓冲区的大小,默认值为10kb。
      2. repository                  :设置文件上传过程中产生临时文件存放的路径。

方法:

 voidsetRepository(java.io.File repository) 
         设置用于临时存储大于配置大小阈值的文件的目录。
 voidsetSizeThreshold(int sizeThreshold) 
         设置直接写入磁盘的临时文件的大小阈值。
  1. setSizeThreshold()             :设置缓冲区的大小
  2. setRepository()                   :设置临时文件存放的路径
  • API的使用的代码
package com.toroidals.uploadfile;

import java.io.File;
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.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

/**
 * 上传文件
 */
public class UploadFile extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		try {
			// 1.创建磁盘文件项工厂
			DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
			// 1.1设置缓冲区的大小:
			diskFileItemFactory.setSizeThreshold(5 * 1024 * 1024); //设置缓冲区的大小为5M		
			// 1.2设置临时文件存放的路径:
			// 获得临时文件存放的路径:
			String tempFilePath = this.getServletContext().getRealPath("/temp");
			System.out.println("tempFilePath" + tempFilePath);
			diskFileItemFactory.setRepository(new File(tempFilePath));
			// 2.创建一个核心的解析类
			ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);
			// 3.利用核心类解析Request,解析后会得到多个部分。返回一个List集合。List集合装的是每个部分的内容(FileItem文件项)。
			List<FileItem> list = fileUpload.parseRequest(request);
			// 4.遍历List集合,会得到代表每个部分的文件项的对象。根据文件项判断是否是文件上传项。
			for (FileItem fileItem : list) {
				// 判断这个文件项是否是普通项还是文件上传项。
				if (fileItem.isFormField()) {
					// 普通项:
					// 接收普通项的值:(接收值不能再使用request.getParameter())
					String name = fileItem.getFieldName();// 获得普通项的名称
					// 获得普通项的值
					String value = fileItem.getString("UTF-8");
					System.out.println(name + "    " + value);
				} else {
					// 文件上传项:
					// 获得文件上传项的文件的名称:
					String filename = new File(fileItem.getName()).getName();
					//获得上传文件的输入流
					InputStream inputStream = fileItem.getInputStream();
				    //获得服务器的绝对路径
					String realPath = this.getServletContext().getRealPath("/file");
					String filePath = realPath + "\\" + filename;
					System.out.println(filePath);
					//创建一个输出流,写入到指定路径
					OutputStream outputStream = new FileOutputStream(filePath);
					//传输数据
					int len;
					byte[] bytes = new byte[8192];
					while((len = inputStream.read(bytes)) != -1) {
						outputStream.write(bytes, 0, len);
					}
					inputStream.close();
					outputStream.close();
					System.out.println("文件上传成功");
				}		
			}
		} catch (FileUploadException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}

临时文件和目标文件一样大 

  • ServletFileUpload:核心解析类

ServletFileUpload:核心解析

 

  • 是用来判断表单的enctype属性是否正确

  • 解析Request对象,返回一个List集合(每个部分的对象FileItem)

  • 设置单个文件的大小

  • 设置上传的文件的总大小

  • 设置中文文件名上传的乱码的问题

设置监听文件上传的进度

去掉 uploadFile form表单的属性 enctype="multipart/form-data" 之后

限制上传你文件大小

 

  • FileItem文件

  • 判断表单项是普通项还是文件上传项。如果为true代表是普通项

普通项的方法:

1.获得普通的名称

1.获得普通项的值

文件上传项:

获得文件上传的文件名

获得文件上传的文件内容

获得文件上传的文件的大小

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

当上传文件的大小超过缓冲区大小就会生成临时文件,上传完成之后调用delete()方法可删除临时文件

fileItem.delete();

package com.toroidals.uploadfile;

import java.io.File;
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.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

/**
 * 上传文件
 */
public class UploadFile extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		try {
			// 判断表单的enctype属性:
			boolean flag = ServletFileUpload.isMultipartContent(request);
			if(!flag){
				// enctype属性不是 multipart/form-data
				request.setAttribute("msg", "表单的格式不正确!");
				request.getRequestDispatcher("/upload/uploadFile.jsp").forward(request, response);
				return;
			}
			// 1.创建磁盘文件项工厂
			DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
			// 1.1设置缓冲区的大小:
			diskFileItemFactory.setSizeThreshold(5 * 1024 * 1024); //设置缓冲区的大小为5M		
			// 1.2设置临时文件存放的路径:
			// 获得临时文件存放的路径:
			String tempFilePath = this.getServletContext().getRealPath("/temp");
			System.out.println("tempFilePath" + tempFilePath);
			diskFileItemFactory.setRepository(new File(tempFilePath));
			// 2.创建一个核心的解析类
			ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);
			// 设置文件上传的文件的最大大小
			//fileUpload.setSizeMax(10*1024*1024);
			// 3.利用核心类解析Request,解析后会得到多个部分。返回一个List集合。List集合装的是每个部分的内容(FileItem文件项)。
			List<FileItem> list = fileUpload.parseRequest(request);
			// 4.遍历List集合,会得到代表每个部分的文件项的对象。根据文件项判断是否是文件上传项。
			for (FileItem fileItem : list) {
				// 判断这个文件项是否是普通项还是文件上传项。
				if (fileItem.isFormField()) {
					// 普通项:
					// 接收普通项的值:(接收值不能再使用request.getParameter())
					String name = fileItem.getFieldName();// 获得普通项的名称
					// 获得普通项的值
					String value = fileItem.getString("UTF-8");
					System.out.println(name + "    " + value);
				} else {
					// 文件上传项:
					// 获得文件上传项的文件的名称:
					String filename = new File(fileItem.getName()).getName();
					//获得上传文件的输入流
					InputStream inputStream = fileItem.getInputStream();
				    //获得服务器的绝对路径
					String realPath = this.getServletContext().getRealPath("/file");
					String filePath = realPath + "\\" + filename;
					System.out.println(filePath);
					//创建一个输出流,写入到指定路径
					OutputStream outputStream = new FileOutputStream(filePath);
					//传输数据
					int len;
					byte[] bytes = new byte[8192];
					while((len = inputStream.read(bytes)) != -1) {
						outputStream.write(bytes, 0, len);
					}
					inputStream.close();
					outputStream.close();
					// 删除临时文件
					fileItem.delete();
					System.out.println("文件上传成功");
				}		
			}
		} catch (FileUploadException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}

 自动删除临时文件

  • JS控制多文件上传

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
	function add(){
		// 获得id为div1的元素:
		var div01Element = document.getElementById("div01");
		div01Element.innerHTML += "<div><input type='file' name='upload'/><input type='button' value='删除' onclick='del(this)'></div>";
	}
	function del(who){
		/* var divv = who.parentNode; 
		divv.parentNode.removeChild(divv); */
		who.parentNode.parentNode.removeChild(who.parentNode);
	}
</script>
</head>
<body>
<h1> ${ msg }</h1>
<h1>多文件上传</h1>
<form action="${ pageContext.request.contextPath }/UploadFile" method="post" enctype="multipart/form-data">
	<input type="button" value="添加" onclick="add()"/>
	<input type="submit" value="上传" /><br>
	<div id="div01">
		<div><input type="file" name="upload"/><input type="button" value="删除" onclick="del(this)"></div>
	</div>
</form>
</body>
</html>
package com.toroidals.uploadfile;

import java.io.File;
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.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

/**
 * 上传文件
 */
public class UploadFile extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		try {
			// 判断表单的enctype属性:
			boolean flag = ServletFileUpload.isMultipartContent(request);
			if(!flag){
				// enctype属性不是 multipart/form-data
				request.setAttribute("msg", "表单的格式不正确!");
				request.getRequestDispatcher("/upload/uploadFile.jsp").forward(request, response);
				return;
			}
			// 1.创建磁盘文件项工厂
			DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
			// 1.1设置缓冲区的大小:
			diskFileItemFactory.setSizeThreshold(5 * 1024 * 1024); //设置缓冲区的大小为5M		
			// 1.2设置临时文件存放的路径:
			// 获得临时文件存放的路径:
			String tempFilePath = this.getServletContext().getRealPath("/temp");
			System.out.println("tempFilePath" + tempFilePath);
			diskFileItemFactory.setRepository(new File(tempFilePath));
			// 2.创建一个核心的解析类
			ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);
			// 设置文件上传的文件的最大大小
			//fileUpload.setSizeMax(10*1024*1024);
			// 3.利用核心类解析Request,解析后会得到多个部分。返回一个List集合。List集合装的是每个部分的内容(FileItem文件项)。
			List<FileItem> list = fileUpload.parseRequest(request);
			// 4.遍历List集合,会得到代表每个部分的文件项的对象。根据文件项判断是否是文件上传项。
			for (FileItem fileItem : list) {
				// 判断这个文件项是否是普通项还是文件上传项。
				if (fileItem.isFormField()) {
					// 普通项:
					// 接收普通项的值:(接收值不能再使用request.getParameter())
					String name = fileItem.getFieldName();// 获得普通项的名称
					// 获得普通项的值
					String value = fileItem.getString("UTF-8");
					System.out.println(name + "    " + value);
				} else {
					// 文件上传项:
					// 获得文件上传项的文件的名称:
					String filename = new File(fileItem.getName()).getName();
					//获得上传文件的输入流
					InputStream inputStream = fileItem.getInputStream();
				    //获得服务器的绝对路径
					String realPath = this.getServletContext().getRealPath("/file");
					String filePath = realPath + "\\" + filename;
					System.out.println(filePath);
					//创建一个输出流,写入到指定路径
					OutputStream outputStream = new FileOutputStream(filePath);
					//传输数据
					int len;
					byte[] bytes = new byte[8192];
					while((len = inputStream.read(bytes)) != -1) {
						outputStream.write(bytes, 0, len);
					}
					inputStream.close();
					outputStream.close();
					// 删除临时文件
					fileItem.delete();
					System.out.println("文件上传成功");
				}		
			}
		} catch (FileUploadException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}

  • 文件上传兼容浏览器问题

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

  • 问题解决
  1. 利用File类的实例方法 getName() 从路径中获取文件名
// 获得文件上传项的文件的名称:
String filename = new File(fileItem.getName()).getName();

     2.判断是否包含\

int idx = filename.lastIndexOf("\\");
if(idx != -1){
    // 使用老版本浏览器:
	filename = filename.substring(idx+1);
}
  • 文件上传同一个目录下文件同名问题

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

  • 解决方案

使用唯一文件名进行解决。

package com.toroidals.utils;

import java.util.UUID;

public class UploadUtils {
	/**
	 * 传递一个文件名,返回一个唯一的文件名。
	 */
	public static String getUniqueName(String fileName) {
		// 在Java的API中有一个类UUID可以产生随机的字符串。aa.txt
		// UUID.randomUUID().toString();
		// 获得文件名的扩展名.
		int idx = fileName.lastIndexOf(".");
		String extetions = fileName.substring(idx);
		return UUID.randomUUID().toString().replace("-", "")+extetions;
	}
	
	/**
	 * 目录分离的算法实现
	 * @param args
	 */
	public static String getDir(String filename, int tierNum) {
		int fileCode = filename.hashCode();
		String path = "";
		for (int i = 0; i < tierNum; i++) {
			path += "\\" + (fileCode & 0xf);
			fileCode = fileCode >>> 4;
		}
		return path;
	}
	
	public static String getDir(String filename) {
		int fileCode = filename.hashCode();
		String path = "";
		for (int i = 0; i < 2; i++) {
			path += "\\" + (fileCode & 0xf);
			fileCode = fileCode >>> 4;
		}
		return path;
	}
}
  • 文件上传同一个目录下文件过多的问题

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

  • 解决方案
  1. 目录分离
    1. 按时间分离              :按月、周、天、小时。
    2. 按用户分离              :按张三、李四。
    3. 按个数分离              :一个目录下存放3000个文件。
    4. 按目录分离算法    :按照某种特定算法进行分离。
      1. 上传一个文件,得到一个唯一的文件名。
      2. 唯一文件名获取其hashCode值。-----int类型的值(32位)
      3. hashCode的值 & 0xf;-----得出的这个值作为一级目录。
      4. hashCode右移4  & 0xf;----得出的这个值作为二级目录。
      5. 以此类推。
  2. 分析算法:

String filename = UploadUtils.getUniqueName(new File(fileItem.getName()).getName());
//获得上传文件的输入流
InputStream inputStream = fileItem.getInputStream();
//获得服务器的绝对路径
String realPath = this.getServletContext().getRealPath("/file");
//根据文件名按按目录分离算法获得目录(2表示2级目录)
String fullDir = realPath + UploadUtils.getDir(filename, 2);
//创建目录
File filedir = new File(fullDir);
if(!filedir.isDirectory()) {
filedir.mkdirs();
}
String fullPath = fullDir + "\\" + filename; 
System.out.println(fullPath);
package com.toroidals.uploadfile;

import java.io.File;
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.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import com.toroidals.utils.UploadUtils;

/**
 * 上传文件
 */
public class UploadFile extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		try {
			// 判断表单的enctype属性:
			boolean flag = ServletFileUpload.isMultipartContent(request);
			if(!flag){
				// enctype属性不是 multipart/form-data
				request.setAttribute("msg", "表单的格式不正确!");
				request.getRequestDispatcher("/upload/uploadFile.jsp").forward(request, response);
				return;
			}
			// 1.创建磁盘文件项工厂
			DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
			// 1.1设置缓冲区的大小:
			diskFileItemFactory.setSizeThreshold(5 * 1024 * 1024); //设置缓冲区的大小为5M		
			// 1.2设置临时文件存放的路径:
			// 获得临时文件存放的路径:
			String tempFilePath = this.getServletContext().getRealPath("/temp");
			System.out.println("tempFilePath" + tempFilePath);
			diskFileItemFactory.setRepository(new File(tempFilePath));
			// 2.创建一个核心的解析类
			ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);
			// 设置文件上传的文件的最大大小
			//fileUpload.setSizeMax(10*1024*1024);
			// 3.利用核心类解析Request,解析后会得到多个部分。返回一个List集合。List集合装的是每个部分的内容(FileItem文件项)。
			List<FileItem> list = fileUpload.parseRequest(request);
			// 4.遍历List集合,会得到代表每个部分的文件项的对象。根据文件项判断是否是文件上传项。
			for (FileItem fileItem : list) {
				// 判断这个文件项是否是普通项还是文件上传项。
				if (fileItem.isFormField()) {
					// 普通项:
					// 接收普通项的值:(接收值不能再使用request.getParameter())
					String name = fileItem.getFieldName();// 获得普通项的名称
					// 获得普通项的值
					String value = fileItem.getString("UTF-8");
					System.out.println(name + "    " + value);
				} else {
					// 文件上传项:
					// 获得文件上传项的文件的名称:
					String filename = UploadUtils.getUniqueName(new File(fileItem.getName()).getName());
					//获得上传文件的输入流
					InputStream inputStream = fileItem.getInputStream();
				    //获得服务器的绝对路径
					String realPath = this.getServletContext().getRealPath("/file");
					//根据文件名按按目录分离算法获得目录(2表示2级目录)
					String fullDir = realPath + UploadUtils.getDir(filename, 2);
					//创建目录
					File filedir = new File(fullDir);
					if(!filedir.isDirectory()) {
						filedir.mkdirs();
					}
					String fullPath = fullDir + "\\" + filename; 
					System.out.println(fullPath);
					//创建一个输出流,写入到指定路径
					OutputStream outputStream = new FileOutputStream(fullPath);
					//传输数据
					int len;
					byte[] bytes = new byte[8192];
					while((len = inputStream.read(bytes)) != -1) {
						outputStream.write(bytes, 0, len);
					}
					inputStream.close();
					outputStream.close();
					// 删除临时文件
					fileItem.delete();
					System.out.println("文件上传成功");
				}		
			}
		} catch (FileUploadException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}

 

 

tempFilePathE:\JAVA2\temp
E:\JAVA2\file\2\1\e0b19dc1c80b40a38a6056bce6969ca4.chm
文件上传成功
E:\JAVA2\file\3\7\aabdba5391b2469f919e7650a48184c8.txt
文件上传成功
E:\JAVA2\file\15\4\52c13bf2cdee49aeb57dfe06c4eed57a.java
文件上传成功
E:\JAVA2\file\14\2\0b2b6ce872a240f1840286af7b5c01c4.jar
文件上传成功
E:\JAVA2\file\0\10\3383c088886f4805a988720c7768c6de.mp4
文件上传成功
  • 文件下载

  1. 文件下载:将服务器上的一个文件,通过流写入到客户端上。
  • 文件下载的方式

  1. 使用超链接的方式实现文件的下载
    1. 在<a href=”文件的路径”>超链接</a>
    2. 注意:超链接的方式,如果浏览器不能识别这种格式的文件,提示下载,如果支持该格式的文件,直接打开。
  2. 通过手动编写代码的方式实现文件的下载
    1. 设置两个头和一个流
      1. Content-Type                     :文件的MIME的类型
      2. Content-Disposition        :浏览器支持该格式的文件,提示下载
      3. 设置代表该文件的输入流(输出流是固定 response.getOutputStream())
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>文件下载:超链接的方式</h1>
<h3><a href="${ pageContext.request.contextPath }/download/1.jpg">1.jpg</a></h3>
<h3><a href="${ pageContext.request.contextPath }/download/aa.zip">aa.zip</a></h3>

<h1>文件下载:手动编码的方式</h1>
<h3><a href="${ pageContext.request.contextPath }/DownloadServlet?filename=1.jpg">1.jpg</a></h3>
<h3><a href="${ pageContext.request.contextPath }/DownloadServlet?filename=aa.zip">aa.zip</a></h3>
</body>
</html>
package com.toroidals.download;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * 文件下载的Servlet
 */
public class DownloadServlet extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 1.接收参数:
		String filename = request.getParameter("filename");
		// 2.下载:设置两个头和一个流
		// 设置Content-Type
		String type = getServletContext().getMimeType(filename);
		response.setContentType(type);
		// 定义一个代表该文件的路径:
		String path = getServletContext().getRealPath("/download");
		File file = new File(path+"/"+filename);
		// 设置Content-Disposition
		response.setHeader("Content-Disposition", "attachment;filename="+filename);
		// 设置一个代表了文件的输入流
		InputStream is = new FileInputStream(file);
		OutputStream os = response.getOutputStream();
		// 两个流对接:
		int len;
		byte[] bytes = new byte[8192];
		while((len = is.read(bytes))!=-1){
			os.write(bytes, 0, len);
		}
		is.close();
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
	{
		doGet(request, response);
	}

}

  • 中文文件的下载

  1. 中文文件的下载:(出现乱码问题)
    1. 不同的浏览器对中文文件的下载的编码不一样的。
      1. IE浏览器采用的是URL编码
      2. Firefox浏览器采用的是Base64编码
    2. 判断客户端使用的浏览器的类型
      1. User-Agent请求头可以获得客户端浏览器信息。
package com.toroidals.download;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.toroidals.download.DownloadUtils;

/**
 * 文件下载的Servlet
 */
public class DownloadServlet extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 1.接收参数:
		String filename = new String(request.getParameter("filename").getBytes("ISO-8859-1"),"UTF-8");
		System.out.println("filename" + filename);
		// 2.下载:设置两个头和一个流
		// 设置Content-Type
		String type = getServletContext().getMimeType(filename);
		response.setContentType(type);
		// 定义一个代表该文件的路径:
		String path = getServletContext().getRealPath("/download");
		File file = new File(path+"/"+filename);
		// 判断浏览器的类型:
		String agent = request.getHeader("User-Agent");
		if(agent.contains("Firefox")){
			// 使用的是Firefox
			filename = DownloadUtils.base64EncodeFileName(filename);
		}else{
			// IE或者其他的浏览器
			filename = URLEncoder.encode(filename, "UTF-8");
		}
		
		// 设置Content-Disposition
		response.setHeader("Content-Disposition", "attachment;filename="+filename);
		// 设置一个代表了文件的输入流
		InputStream is = new FileInputStream(file);
		OutputStream os = response.getOutputStream();
		// 两个流对接:
		int len = 0;
		byte[] b = new byte[1024];
		while((len = is.read(b))!=-1){
			os.write(b, 0, len);
		}
		is.close();
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
	{
		doGet(request, response);
	}

}
  • 给定目录下的文件下载

  • 需求描述

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

广度优先遍历:先将根节点入队,再从队列中取出一个节点,将该节点下所有非叶子节点入队,叶子结点取出另存;再从队列中取出一个节点,将该节点下所有非叶子节点入队,叶子结点取出另存...

深度优先遍历:采用递归的方式

 注意:以为此次传的是绝对路径,get请求传参时参数中包含特殊字符“/”,所以在传参之前先解码,在后台接收参数时先编码

<h4><a href="${ pageContext.request.contextPath }/DownloadListServlet?filename=<%=URLEncoder.encode(f.getCanonicalPath(), "UTF-8")%>"> <%= f.getName() %></a></h4>
// 接收参数:
String path = URLDecoder.decode(request.getParameter("filename"), "UTF-8");
<%@page import="java.io.File"%>
<%@page import="java.net.URLEncoder"%>
<%@page import="java.util.*"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<<h1>树形遍历</h1>
<%
	// 1.创建一个队列:
	Queue<File> queue = new LinkedList<File>();
	// 2.先将跟节点入队:
	File root = new File("E:\\work_space\\javaEclipse\\UploadDownload\\WebContent\\downloadList");
	queue.offer(root);
	// 判断这个队列是否为空,不为空需要进行遍历:
	while(!queue.isEmpty()){
		// 将跟节点出队:
		File file = queue.poll();
		// 获得跟节点下的所有子节点:
		File[] files = file.listFiles();
		// 遍历所有子节点:
		for(File f:files){
			// 判断该节点是否为叶子节点:
			if(f.isFile()){
%>
<h4><a href="${ pageContext.request.contextPath }/DownloadListServlet?filename=<%=URLEncoder.encode(f.getCanonicalPath(), "UTF-8")%>"> <%= f.getName() %></a></h4>
<%
			}else{
				queue.offer(f);
			}
		}
	}
%>
</body>
</html>
package com.toroidals.download;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 树形的文件下载的代码实现
 */
public class DownloadListServlet extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 接收参数:
		String path = URLDecoder.decode(request.getParameter("filename"), "UTF-8");
		System.out.println(path);
		File file = new File(path);
		// 实现文件下载:设置两个头和一个流:
		// 获得文件名
		String filename = file.getName();
		response.setContentType(getServletContext().getMimeType(filename));
		// 设置另一个头:
		String agent = request.getHeader("User-Agent");
		if(agent.contains("Firefox")){
			filename = DownloadUtils.base64EncodeFileName(filename);
		}else{
			filename = URLEncoder.encode(filename, "UTF-8");
			filename = filename.replace("+", " ");
		}
		response.setHeader("Content-Disposition", "attachment;filename="+filename);
		// 设置输入流:
		InputStream is = new FileInputStream(file);
		OutputStream os = response.getOutputStream();
		int len = 0;
		byte[] b = new byte[1024];
		while((len = is.read(b))!=-1){
			os.write(b, 0, len);
		}
		is.close();
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		doGet(request, response);
	}

}

 

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐