1.問題
SpringBoot項目需要下載一個靜態模板文件 demo.xlsx,這個文件放在 resources/static/excel/demo.xlsx 目錄下面。但是項目是以 jar 包的形式線上運行。而jar包作為壓縮包是無法直接獲取的。只能獲取其中的流InputStream,而無法獲取 File類型,而文件下載時又需要 response.addHeader("Content-Length",String.valueOf(file.length()));
否則文件下載會報錯,嘗試修復。如下圖所示
所以二者相悖,然后搜索到雖然 stream.available() 也是可以獲取預估的文件大小,但是對於網絡下載的文件並不十分准確,受到網絡影響很大。而且其返回的是 int類型(-2,147,483,648,2,147,483,647),所以最大也就是 214M的大小,而file.length()返回的是long類型。
綜上所述,搜了一上午,基本上帖子都沒什么用,直到我搜到下面這個解決辦法,它總結了諸多問題,然后給出一個非常好的解決辦法,見下面。
2.解決辦法
主要就是參考 spring boot中Excel文件下載踩坑大全 感謝大佬。解決思路就是使用 spring提供的工具類FileCopyUtils.copyToByteArray
一勞永逸的解決問題,適用於小文件下載。所以我最后的下載工具類代碼是如下:
public static HttpServletResponse downloadFile(HttpServletResponse response, String fileName) {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
// 直接獲取流
inputStream = FileUtil.class.getClassLoader().getResourceAsStream("static/excel/" + fileName);
response.setContentType("application/octet-stream");
String name = java.net.URLEncoder.encode(fileName, "UTF-8");
response.setHeader("Content-Disposition", "attachment;filename=" + java.net.URLDecoder.decode(name, "ISO-8859-1") );
outputStream = response.getOutputStream();
if( inputStream != null) {
// 調用工具類
byte[] results = FileCopyUtils.copyToByteArray(inputStream);
outputStream.write(results);
outputStream.flush();
}
} catch (IOException e) {
log.error("文件下載失敗, e");
}
finally {
IOUtils.closeQuietly(outputStream);
IOUtils.closeQuietly(inputStream);
}
}
需要明確的是:對於下載,不需要返回值。因為,本身就已經把數據輸入到response里面。