文件下载至内存溢出

 

同事文章:

部分项目的文件下载处理方式如下:

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
byte[] stb = new byte[bis.available()];
int length = 0;
length = bis.read(stb);
bis.close();
response.setContentLength(length);
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream(), length);
bos.write(stb, 0, length);
bos.close();

这种方式下载几十KB的小文件没有什么大碍,但下载大文件(甚至到几十MB)则存在重大的性能隐患

对于下载大文件的场景,代码标红部分,会创建一个巨大的字节数组,并且将整个文件读入内存中。可想而知,当处于文件下载高峰期,将会对系统运行的稳定性造成严重影响!

解决方法:

FileInputStream is = new FileInputStream(new File(filePath));
response.setContentLength(is.available());
FileCopyUtils.copy(is, response.getOutputStream());

将开篇的整段代码,替换为这三行代码,问题解决。

第二行的作用是为了在下载提示框显示文件大小(如图),不写也可以。

最简化可以只写一句(提示框不显示文件大小):FileCopyUtils.copy(new FileInputStream(new File(filePath)), response.getOutputStream());

FileCopyUtils 全名 org.springframework.util.FileCopyUtils

使用了分块的方式进行流复制,并在完成后关闭流,实现类似我们一般的上传处理。每次复制4k,大概如下实现。

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
int bytesRead;
byte[] buffer = new byte[4096];
while ((bytesRead = bis.read(buffer, 0, 4096)) != -1) {
  bos.write(buffer, 0, bytesRead);
}
bos.close();
bis.close();

你可能感兴趣的:(文件下载)