JAVA實現zip壓縮需要注意的問題


近來對院社二維碼平台進行2.0升級改造。於昨日踩到一個巨坑。特此記錄。。。

需求源於院社編輯在批量下載二維碼的時候,系統后台需要對所要下載的二維碼進行重命名和zip打包壓縮。

系統測試的時候發現:首次請求批量下載時,也即壓縮文件還未生成時,后台可以正常壓縮文件並提供下載。但是第二次請求批量下載時,網頁一直無反應。。。

嘗試了幾次后仍舊沒反應。只好查看tomcat日志,驚奇的發現日志只寫了一半,后半部分丟失(第一次遇到這種情況)==|||

不過老天爺保佑,寫入的一部分顯示:No space left device.

我擦!硬盤滿了?昨天還有68%的余量。今天就沒了?

迅速df du命令走起。du顯示並沒有占滿。但是df顯示已經100%。這是搞毛。。

google一下,發現du df顯示結果不一樣的原因可能是有文件句柄沒有釋放,文件仍舊被進程占用。df統計的是硬盤實際占用,而du並不包括已經標記刪除卻仍舊被進程占用,實際上並未物理刪除的文件。(文件物理刪除和標識為deleted不是一個概念)

接着調用lsof | grep deleted查看文件占用情況。。果然那幾個zip文件size已經突破天際了。。

看來是java對zip文件打包時出錯了。陷入了死循環???

由於zip打包源碼是同事提供的,並沒有深入了解。不得不扒開package,查看到底是個啥子邏輯。

經過一番折騰。終於發現問題。

舉個例子:

a文件下有1.jpg 2.jpg兩個文件

在第一次請求批量下載時,生成了b.zip文件。

如此a文件夾下就有了1.jpg 2.jpg b.zip文件了

根據源碼邏輯,首先會對a文件夾進行遍歷搜索,然后將每個文件逐個加入zip文件中。

那么,第二次請求時,從表面上看,可能會粗略的以為b.zip會被覆蓋掉,替換成新b.zip,里面包括1.jpg 2.jpg 和舊的b.zip。

大錯特錯!

文件在進行寫操作時,始終是對同一個b.zip在操作!

分解一下過程。首先在遍歷a文件夾得到三個文件名的列表:1 2 b

創建新b時,舊b文件會被刪除,但是b這個文件名仍舊保留在上面的文件列表中。

接下來,添加1到新b,添加2到新b。

在添加舊B的時候,實則在對新B操作!!如果從文件讀寫指針的角度來看,如下圖所示

read              write

   1      2      (12)

可以看到,由於是在對同一個文件操作,read指針永遠不可能趕上write,也即EOF,那么這個寫就永無止境。

所以解決bug的方法是:把要打包的文件和目標zip文件放在兩個不同的文件夾下面。這樣就不會始終對同一個zip文件又讀又寫了。

 

此外,我還在windows平台上進行了測試。發現一個很詭異的現象。在windows上文件能夠正常下載,且不會出現磁盤容量爆棚的情況。但是:

1)新打包的b.zip里面還有一個b.zip。

2)外層的b.zip可以正常解壓,里層的b.zip也可以解壓和查看。但是里層的b.zip解壓時會報文件末端錯誤。

3)里層的b.zip還有一個b.zip,暫且叫做里里層b.zip。這個里里層b.zip就完全打不開了。

4)用資源管理器查看tomcat所掌握的資源句柄,仍舊包括這個最外層的b.zip。也就是即便client完成了下載,服務端也沒有釋放這個資源。

可以說,windows遇到了和linux平台一樣的問題。但是可能因為windows操作系統的文件系統具體細節的處理方式不同,導致出現了最后這樣一個相對詭異的結果。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM