背景:
使用url通過httpClient的get方法,從oss下載pdf文件,被下載的文件通過瀏覽器能正常查看和下載
問題:
偶爾會出現一個下載文件爲0KB的情況
代碼:
GetMethod httpGet = new GetMethod(strUrlPath);
InputStream in = null;
FileOutputStream out = null;
try {
HttpClient httpClient = new HttpClient();
httpClient.executeMethod(httpGet);
in = httpGet.getResponseBodyAsStream();
out = new FileOutputStream(new File(strLocalPath));
byte[] b = new byte[1024];
int len = 0;
while ((len = in.read(b)) != -1) {
out.write(b, 0, len);
}
in.close();
out.close();
} catch (Exception e) {
log.error("httpClient下載文件失敗", e);
} finally {
httpGet.releaseConnection();
try {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
} catch (Exception e1) {
log.error("文件流信息關閉失敗", e1);
}
}
分析過程:
- 因爲 FileOutputStream 沒有調用flush方法,認爲是數據未從緩存區刷入到系統,就關閉了輸出流,導致文件爲0KB。結果發現分析錯誤,通過查看源碼發現 flush 方法是 OutputStream 的方法,是個空實現。FileOutputStream 繼承了 OutputStream 並未重寫其 flush 方法,所以 FileOutputStream 是直接寫入系統緩存。
- 通過查看資料,瞭解到輸出流持久化文件是一個異步的過程。首先輸出流將字節寫入系統緩存,系統緩存會直接返回寫入結果。然後系統緩存會排隊將內容持久化。那我們可以將該過程變爲一個同步過程麼?答案是可以的。通過調用輸出流的 FileOutputStream.getFD().sync() 方法,同步等待文件持久化之後返回結果。至此問題解決。
注意:使用 FileOutputStream.getFD().sync() 同步方法,對文件寫入的性能影響較大,是否需要使用還需要根據具體業務進行權衡。