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

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

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

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

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

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

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

迅速df du命令走起。du顯示並無佔滿。可是df顯示已經100%。這是搞毛。。spa

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操做系統的文件系統具體細節的處理方式不一樣,致使出現了最後這樣一個相對詭異的結果。

相關文章
相關標籤/搜索