admin管理员组

文章数量:1537955

解决ie打开本该下载的文件问题

背景:

上周项目出现了一个bug,一般下载直接写个如下的<a>标签即可

<a href="https://caomei.mall/files/1/5/files/menu.pdf">download</a>

然而发现.txt,.jpg和.pdf等格式的文件会在浏览器直接打开而不是下载.然后百度到w3cSchol.<a>标签有一个download属性.

<a href="/images/myw3schoolimage.jpg" download="w3logo">

官方解释:

定义和用法

download 属性规定被下载的超链接目标。

在 <a> 标签中必须设置 href 属性。

该属性也可以设置一个值来规定下载文件的名称。所允许的值没有限制,浏览器将自动检测正确的文件扩展名并添加到文件 (.img, .pdf, .txt, .html, 等等)。


然而兼容性并不好,崩溃,我可是要支持ie的人儿啊.


继续搜索,终于,修改response的头部信息,将文件内容读取写出输出流

@RequestMapping(value = "/downFile", method = RequestMethod.POST)
	@ResponseBody
	public void downFile(HttpServletRequest request, HttpServletResponse response, String fileUrl) {
		try {
			// path是指欲下载的文件的路径。
			File file = new File(fileUrl);
			// 取得文件名。
			String filename = file.getName();
			// 取得文件的后缀名。
			//String ext = filename.substring(filename.lastIndexOf(".") + 1).toUpperCase();
			// 以流的形式下载文件。
			InputStream fis = new BufferedInputStream(new FileInputStream(fileUrl));
			byte[] buffer = new byte[fis.available()];
			fis.read(buffer);
			fis.close();
			// 清空response
			response.reset();
			// 设置response的Header
			response.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes()));
			response.addHeader("Content-Length", "" + file.length());
			OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
			response.setContentType("application/octet-stream");
			outputStream.write(buffer);
			outputStream.flush();
			outputStream.close();
		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}

然而测试妹纸马上就叫我了,.avi格式的文件下载失败了,吓得我赶紧去线上瞅瞅,内存溢出了


不禁感叹,这小小的下载事情真多.

继续查找原因,发现这种方式下载小一点的文件,或者服务器配置高一点看不出啥来,但是当要下载的文件很大的时候,将字节数组吃进内存,系统运行就会GG了.

所以,一点点的将内容写进内存咯,测试okay.

@RequestMapping(value = "/downFile", method = RequestMethod.GET)
	@ResponseBody
	public void downFile(HttpServletRequest request, HttpServletResponse response, String fileUrl) {
		try {
			Video v = new Video();
			v.setRelname(fileUrl);
			Video video = videoService.selectOne(v);
			String path = GlobalData.FTP_BASEPATH + File.separator + video.getPath() + File.separator + video.getRelname();
			// path是指欲下载的文件的路径。
			File file = new File(path);
			// 取得文件名。
			String filename = video.getName();
			//filename转码,解决中文文件名的问题
			response.setHeader("Content-Disposition", "attachment;filename=\"" + new String(filename.getBytes("GB2312"), "ISO_8859_1")+"\"");
			response.setHeader("Content-Length", "" + file.length());
			//告诉浏览器数据是二进制流
			response.setContentType("application/octet-stream");
			// 以流的形式下载文件。
			BufferedInputStream fis = new BufferedInputStream(new FileInputStream(path));
			byte[] b = new byte[1024];
			int length = 0;
			OutputStream out = response.getOutputStream();
			while ((length = fis.read(b))>0){
				out.write(b, 0, length);
			}
			fis.close();
			out.close();
		} catch (IOException ex) {
			logger.error("下载文件失败:",ex);
		}
	}
网上提示,还可以使用org.springframework.util.FileCopyUtils修改原来的代码,和上述代码的内部实现差不多.使用了分块的方式进行流复制,并在完成后关闭流,实现类似我们一般的上传处理。
FileInputStream is = new FileInputStream(new File(filePath));
response.setContentLength(is.available());
FileCopyUtils.copy(is, response.getOutputStream());

本文标签: 文件