0
点赞
收藏
分享

微信扫一扫

web项目下载文件,总有人喜欢先在本地生成临时文件,在此验证其效率,看是否可以进一步优化

zhongjh 2022-04-04 阅读 59
java

目录

写在前面

公共文件下载方法

生成临时文件方式下载

 测试

 直接输出流转输入流的方式下载

测试

总结


写在前面

有很多互联网web项目,做文件打包下载的时候,可能需要先从文件服务器下载所有文件放到临时目录,然后再将目录打包成zip临时文件,然后再返回给前端。

其实这种方式是可以实现业务逻辑的,但是事实上效率真的高吗?

也许可以优化!

公共文件下载方法


	/**
	 * 文件下载
	 */
	public void downloadFile(HttpServletResponse response, BufferedInputStream bis, String fileName) {
		OutputStream os = null;
		BufferedOutputStream bos = null;
		try {
			//文件流的声明
			//重点突出(特别注意),通过response获取的输出流,作为服务端向客户端浏览器输出内容的通道
			os = response.getOutputStream();
			// 为了提高效率使用缓冲区流
			bos = new BufferedOutputStream(os);
			// 对文件名进行编码处理中文问题
			// 处理中文文件名的问题
			fileName = java.net.URLEncoder.encode(fileName, "UTF-8");
			// 处理中文文件名的问题
			fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), "GBK");
			response.reset();
			response.setCharacterEncoding("UTF-8");
			// 不同类型的文件对应不同的MIME类型
			response.setContentType("application/x-msdownload");
			response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
			int bytesRead;
			byte[] buffer = new byte[4096];
			//重点
			while ((bytesRead = bis.read(buffer)) != -1) {
				// 将文件发送到客户端
				bos.write(buffer, 0, bytesRead);
				bos.flush();
			}

		} catch (Exception ex) {
			throw new RuntimeException(ex);
		} finally {
			try {
				if (null != bis) {
					bis.close();
				}
				if (null != bos) {
					bos.close();
				}
				if (null != os) {
					os.close();
				}
			} catch (Exception ex) {
				System.out.println(ex.getMessage());
			}
		}
	}

生成临时文件方式下载


	/**
	 * 测试文件上传,需要生成本地文件
	 */
	@RequestMapping(value = "/getZipFiles2",method =RequestMethod.GET)
	@ResponseBody
	public void getZipFiles2(HttpServletResponse response) throws Exception {
		// 获取三个文件的字符流
		File file1 = new File("D:\\test\\1.exe");
		File file2 = new File("D:\\test\\2.exe");
		File file3 = new File("D:\\test\\3.exe");
		BufferedInputStream bis1 = new BufferedInputStream(new FileInputStream(file1), 1024);
		BufferedInputStream bis2 = new BufferedInputStream(new FileInputStream(file2), 1024);
		BufferedInputStream bis3 = new BufferedInputStream(new FileInputStream(file3), 1024);
		List<BufferedInputStream> fileList = new ArrayList();
		fileList.add(bis1);
		fileList.add(bis2);
		fileList.add(bis3);
		//创建zip输出流
		ZipOutputStream out = new ZipOutputStream(new FileOutputStream("D:\\test\\1.zip"));
		//创建缓冲输出流
		BufferedOutputStream bos = new BufferedOutputStream(out);
		for (int i = 0; i < fileList.size(); i++) {
			out.putNextEntry(new ZipEntry(i+".exe"));
			int len=-1;
			//将源文件写入到zip文件中
			byte[] buf = new byte[1024];
			while ((len = fileList.get(i).read(buf)) != -1) {
				bos.write(buf,0,len);
			}
			fileList.get(i).close();
		}
		bos.close();
		// 输出流转输入流
		downloadFile(response, new BufferedInputStream(new FileInputStream("D:\\test\\1.zip"), 1024), "1.zip");
	}

 测试

三个文件压缩后的大小大概是192MB,其实算比较大了。

我们看到总用时是8.83秒(博主多次测试,大概都是这个时间)。

 

 直接输出流转输入流的方式下载

	/**
	 * 测试文件上传,不需要生成本地文件
	 */
	@RequestMapping(value = "/getZipFiles1",method =RequestMethod.GET)
	@ResponseBody
	public void getZipFiles1(HttpServletResponse response) throws Exception {
		// 获取三个文件的字符流
		File file1 = new File("D:\\test\\1.exe");
		File file2 = new File("D:\\test\\2.exe");
		File file3 = new File("D:\\test\\3.exe");
		BufferedInputStream bis1 = new BufferedInputStream(new FileInputStream(file1), 1024);
		BufferedInputStream bis2 = new BufferedInputStream(new FileInputStream(file2), 1024);
		BufferedInputStream bis3 = new BufferedInputStream(new FileInputStream(file3), 1024);
		List<BufferedInputStream> fileList = new ArrayList();
		fileList.add(bis1);
		fileList.add(bis2);
		fileList.add(bis3);
		// 压缩成一个zip
		//创建一个ByteArray输出流
		ByteArrayOutputStream arrayOutputStream =new ByteArrayOutputStream();
		//创建zip输出流
		ZipOutputStream out = new ZipOutputStream(arrayOutputStream);
		//创建缓冲输出流
		BufferedOutputStream bos = new BufferedOutputStream(out);
		for (int i = 0; i < fileList.size(); i++) {
			out.putNextEntry(new ZipEntry(i+".exe"));
			int len=-1;
			//将源文件写入到zip文件中
			byte[] buf = new byte[1024];
			while ((len = fileList.get(i).read(buf)) != -1) {
				bos.write(buf,0,len);
			}
			fileList.get(i).close();
		}
		bos.close();
		// 输出流转输入流
		InputStreamSource inputStreamSource = new ByteArrayResource(arrayOutputStream.toByteArray());
		downloadFile(response, new BufferedInputStream(inputStreamSource.getInputStream()), "1.zip");
	}

测试

三个文件压缩后的大小大概是192MB,其实算比较大了。

我们看到总用时是6.29秒(博主多次测试,大概都是这个时间)。

总结

其实文件下载,没必要先生成一个本地文件。

完全可以将输出流转成输入流,或者将输入流转成输出流,直接在内存中做转换,没有中间商赚差价!

事实证明,没有中间商赚差价可以提高大概20%-30%的响应速度!

其中输入流输出流的互相转换方式,请查看:

java输入流输出流的互相转换(不需要经过临时文件啦超方便)_秃了也弱了。的博客-CSDN博客

举报

相关推荐

0 条评论