文件下载

Posted Actexpler

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了文件下载相关的知识,希望对你有一定的参考价值。

经过不懈努力终于 实现了简单的文件下载,一直卡在中文文件名乱码,以及文件输出的问题上

文件的下载
[1] 简介
> 将服务器中的文件下载到本地。
> 一般情况下资源所在的链接发送给浏览器,浏览器就会自动下载。
但是当浏览器支持当前文件的格式,浏览器会自动打开文件,而不会弹出下载窗口。
> 直接将资源放在项目的目录下,浏览器可以直接访问到资源。
所以一般我们下载的资源不能让浏览器直接访问到。
 
[2] 下载所需要的内容
1.获取到文件的流
2.设置两个响应头
 
[3] 下载相关的两个响应头
1) 文件类型 Content-Type --> 文件的MIME类型
Content-Type:告诉浏览器文件的类型,需要设置一个MIME值
response.setContent-Type("MIME值")
通过servletContext.getMimeType(path)方法可以直接获取文件的MIME类型
 
2) 下载文件的信息 Content-Disposition --> attachment; filename=文件名
Content-Disposition告诉浏览器如何处理文件,
attachment 告诉浏览器这个文件是一个附件的形式发给你的,需要你做下载的操作
filename 告诉浏览器下载文件的名字
 
3) 乱码的问题,当将文件的名字设置为中文,浏览器正常显示文件的名字。
因为从服务器向浏览器发送中文时,需要对内容进行URL编码。
> 大部分浏览器使用如下方式即可解决乱码问题:URLEncoder.encode(fileName, "utf-8");
> 但是火狐默认以Base64来解码的,所以要为火狐单独处理。
 
> 可以使用如下代码来判断浏览器的类型,然后进行不同的编码处理
 // 请求客户端操作系统的信息  
	    final String userAgent = request.getHeader("USER-AGENT");  
	    if(userAgent.contains("Firefox")){
			//是火狐浏览器,使用BASE64编码
			fileName = "=?utf-8?b?"+new BASE64Encoder().encode(fileName.getBytes("utf-8"))+"?=";
		}else{
			//给文件名进行URL编码
			//URLEncoder.encode()需要两个参数,第一个参数时要编码的字符串,第二个是编码所采用的字符集
			fileName = URLEncoder.encode(fileName, "utf-8");
		}

 

> 还有一种不太讲理的方式,谁问跟谁急。反正好使
- 向将字符串用gbk进行解码,然后在使用iso8859-1进行编码
fileName = new String(fileName.getBytes("gbk"),"iso8859-1");
 
 
附文件下载源码
package com.neuedu.downFileLoad;

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

import javax.servlet.ServletContext;
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.io.IOUtils;
import org.apache.commons.lang.StringUtils;

import sun.misc.BASE64Encoder;
import sun.nio.ch.IOUtil;

@WebServlet("/MyFileDownload")
public class MyFileDownload extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//获取文件路径
		ServletContext servletContext = request.getServletContext();
		String fileName="风吹麦浪.mp3";
		String realPath = servletContext.getRealPath("/WEB-INF/"+fileName);	
		//获取文件名
		File file=new File(realPath);
		String mimeType = servletContext.getMimeType(fileName);
		 // 请求客户端操作系统的信息  
	    final String userAgent = request.getHeader("USER-AGENT");  
	    if(userAgent.contains("Firefox")){
			//是火狐浏览器,使用BASE64编码
			fileName = "=?utf-8?b?"+new BASE64Encoder().encode(fileName.getBytes("utf-8"))+"?=";
		}else{
			//给文件名进行URL编码
			//URLEncoder.encode()需要两个参数,第一个参数时要编码的字符串,第二个是编码所采用的字符集
			fileName = URLEncoder.encode(fileName, "utf-8");
		}
		//输入流
		InputStream in=new FileInputStream(file);
		//设置响应头  
		 response.setContentType(mimeType);
		    response.addHeader("Content-Disposition", "attachment; filename=" + fileName);  
		    
//		//输出流
//		PrintWriter out=response.getWriter();
//		IOUtils.copy(in, out);
		    byte[] b = new byte[100];  
		    int len;  
		    while ((len = in.read(b)) > 0) {  
		        response.getOutputStream().write(b, 0, len);  
		    }  
		    in.close();  
	}


	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

当然这只是简单的实现文件的下载,在实际的项目中可能需要从数据库或者是从文件夹读取多个要下载的文件,那就不能像上面的代码那样在后台写出文件名,而应该去文件或者数据库中读取。

 
 

以上是关于文件下载的主要内容,如果未能解决你的问题,请参考以下文章

在Tomcat的安装目录下conf目录下的server.xml文件中增加一个xml代码片段,该代码片段中每个属性的含义与用途

代码片段 PHP,预期文件结尾,我错在哪里?

代码适用于与单个 html 文件不同的堆栈片段

VS code自定义用户代码片段snippet

Java itext为pdf 文件添加水印核心功能代码片段

VSCode自定义代码片段——声明函数