文件下载功能是web开发中经常使用到的功能,使用HttpServletResponse对象就可以实现文件的下载
文件下载功能的实现思路:
1.获取要下载的文件的绝对路径
2.获取要下载的文件名
3.设置content-disposition响应头控制浏览器以下载的形式打开文件
4.获取要下载的文件输入流
5.创建数据缓冲区
6.通过response对象获取OutputStream流
7.将FileInputStream流写入到buffer缓冲区
8.使用OutputStream将缓冲区的数据输出到客户端浏览器
范例:使用Response实现文件下载
1 package gacl.response.study; 2 import java.io.FileInputStream; 3 import java.io.FileNotFoundException; 4 import java.io.FileReader; 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.io.OutputStream; 8 import java.io.PrintWriter; 9 import java.net.URLEncoder; 10 import javax.servlet.ServletException; 11 import javax.servlet.http.HttpServlet; 12 import javax.servlet.http.HttpServletRequest; 13 import javax.servlet.http.HttpServletResponse; 14 /** 15 * @author gacl 16 * 文件下载 17 */ 18 public class ResponseDemo02 extends HttpServlet { 19 20 public void doGet(HttpServletRequest request, HttpServletResponse response) 21 throws ServletException, IOException { 22 downloadFileByOutputStream(response);//下载文件,通过OutputStream流 23 } 24 25 /** 26 * 下载文件,通过OutputStream流 27 * @param response 28 * @throws FileNotFoundException 29 * @throws IOException 30 */ 31 private void downloadFileByOutputStream(HttpServletResponse response) 32 throws FileNotFoundException, IOException { 33 //1.获取要下载的文件的绝对路径 34 String realPath = this.getServletContext().getRealPath("/download/1.JPG"); 35 //2.获取要下载的文件名 36 String fileName = realPath.substring(realPath.lastIndexOf("\\")+1); 37 //3.设置content-disposition响应头控制浏览器以下载的形式打开文件 38 response.setHeader("content-disposition", "attachment;filename="+fileName); 39 //4.获取要下载的文件输入流 40 InputStream in = new FileInputStream(realPath); 41 int len = 0; 42 //5.创建数据缓冲区 43 byte[] buffer = new byte[1024]; 44 //6.通过response对象获取OutputStream流 45 OutputStream out = response.getOutputStream(); 46 //7.将FileInputStream流写入到buffer缓冲区 47 while ((len = in.read(buffer)) > 0) { 48 //8.使用OutputStream将缓冲区的数据输出到客户端浏览器 49 out.write(buffer,0,len); 50 } 51 in.close(); 52 } 53 54 public void doPost(HttpServletRequest request, HttpServletResponse response) 55 throws ServletException, IOException { 56 doGet(request, response); 57 } 58 }
运行结果如下所示:
范例:使用Response实现中文文件下载
下载中文文件时,需要注意的地方就是中文文件名要使用URLEncoder.encode方法进行编码(URLEncoder.encode(fileName, "字符编码")),否则会出现文件名乱码。
1 package gacl.response.study; 2 import java.io.FileInputStream; 3 import java.io.FileNotFoundException; 4 import java.io.FileReader; 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.io.OutputStream; 8 import java.io.PrintWriter; 9 import java.net.URLEncoder; 10 import javax.servlet.ServletException; 11 import javax.servlet.http.HttpServlet; 12 import javax.servlet.http.HttpServletRequest; 13 import javax.servlet.http.HttpServletResponse; 14 /** 15 * @author gacl 16 * 文件下载 17 */ 18 public class ResponseDemo02 extends HttpServlet { 19 20 public void doGet(HttpServletRequest request, HttpServletResponse response) 21 throws ServletException, IOException { 22 downloadChineseFileByOutputStream(response);//下载中文文件 23 } 24 25 /** 26 * 下载中文文件,中文文件下载时,文件名要经过URL编码,否则会出现文件名乱码 27 * @param response 28 * @throws FileNotFoundException 29 * @throws IOException 30 */ 31 private void downloadChineseFileByOutputStream(HttpServletResponse response) 32 throws FileNotFoundException, IOException { 33 String realPath = this.getServletContext().getRealPath("/download/张家界国家森林公园.JPG");//获取要下载的文件的绝对路径 34 String fileName = realPath.substring(realPath.lastIndexOf("\\")+1);//获取要下载的文件名 35 //设置content-disposition响应头控制浏览器以下载的形式打开文件,中文文件名要使用URLEncoder.encode方法进行编码,否则会出现文件名乱码 36 response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(fileName, "UTF-8")); 37 InputStream in = new FileInputStream(realPath);//获取文件输入流 38 int len = 0; 39 byte[] buffer = new byte[1024]; 40 OutputStream out = response.getOutputStream(); 41 while ((len = in.read(buffer)) > 0) { 42 out.write(buffer,0,len);//将缓冲区的数据输出到客户端浏览器 43 } 44 in.close(); 45 } 46 47 public void doPost(HttpServletRequest request, HttpServletResponse response) 48 throws ServletException, IOException { 49 doGet(request, response); 50 } 51 }
运行结果如下所示:
文件下载注意事项:编写文件下载功能时推荐使用OutputStream流,避免使用PrintWriter流,因为OutputStream流是字节流,可以处理任意类型的数据,而PrintWriter流是字符流,只能处理字符数据,如果用字符流处理字节数据,会导致数据丢失。
范例:使用PrintWriter流下载文件
1 package gacl.response.study; 2 import java.io.FileInputStream; 3 import java.io.FileNotFoundException; 4 import java.io.FileReader; 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.io.OutputStream; 8 import java.io.PrintWriter; 9 import java.net.URLEncoder; 10 import javax.servlet.ServletException; 11 import javax.servlet.http.HttpServlet; 12 import javax.servlet.http.HttpServletRequest; 13 import javax.servlet.http.HttpServletResponse; 14 /** 15 * @author gacl 16 * 文件下载 17 */ 18 public class ResponseDemo02 extends HttpServlet { 19 20 public void doGet(HttpServletRequest request, HttpServletResponse response) 21 throws ServletException, IOException { 22 downloadFileByPrintWriter(response);//下载文件,通过PrintWriter流 23 } 24 25 /** 26 * 下载文件,通过PrintWriter流,虽然也能够实现下载,但是会导致数据丢失,因此不推荐使用PrintWriter流下载文件 27 * @param response 28 * @throws FileNotFoundException 29 * @throws IOException 30 */ 31 private void downloadFileByPrintWriter(HttpServletResponse response) 32 throws FileNotFoundException, IOException { 33 String realPath = this.getServletContext().getRealPath("/download/张家界国家森林公园.JPG");//获取要下载的文件的绝对路径 34 String fileName = realPath.substring(realPath.lastIndexOf("\\")+1);//获取要下载的文件名 35 //设置content-disposition响应头控制浏览器以下载的形式打开文件,中文文件名要使用URLEncoder.encode方法进行编码 36 response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(fileName, "UTF-8")); 37 FileReader in = new FileReader(realPath); 38 int len = 0; 39 char[] buffer = new char[1024]; 40 PrintWriter out = response.getWriter(); 41 while ((len = in.read(buffer)) > 0) { 42 out.write(buffer,0,len);//将缓冲区的数据输出到客户端浏览器 43 } 44 in.close(); 45 } 46 47 public void doPost(HttpServletRequest request, HttpServletResponse response) 48 throws ServletException, IOException { 49 doGet(request, response); 50 } 51 }
运行结果如下:
正常弹出下载框,此时我们点击【保存】按钮将文件下载下来,如下所示:
可以看到,只下载了5.25MB,而这张图片的原始大小却是
这说明在下载的时候数据丢失了,所以下载不完全,所以这张图片虽然能够正常下载下来,但是却是无法打开的,因为丢失掉了部分数据,如下所示:
所以使用PrintWriter流处理字节数据,会导致数据丢失,这一点千万要注意,因此在编写下载文件功能时,要使用OutputStream流,避免使用PrintWriter流,因为OutputStream流是字节流,可以处理任意类型的数据,而PrintWriter流是字符流,只能处理字符数据,如果用字符流处理字节数据,会导致数据丢失。