Problem
我們有個功能會透過web上傳到壓縮檔到server side,接著解壓縮,最後將解壓縮的資料夾移動到某個目錄。某天發現這個功能會隨機發生移動失敗的問題,最早我使用的API像這樣:
File src = new File("src"); File dest = new File("dest"); boolean result = src.renameTo(dest);
然而這種作法只能知道成功或失敗,並無法知道原因;因此我將做法改為:
File src = new File("src"); File dest = new File("dest"); try { Files.move(src, dest); } catch( Exception e ) { // handle exception }
最後接到一個沒有原因的AccessDeniedException。
Debug & Workaround
我做過以下推測與實驗:
- unzip程式沒關閉檔案串流: 沒關閉檔案串流也會造成沒有原因的AccessDeniedException;但review程式碼與測試案例認為應不是這問題。
- 手動或透過另一隻程式去鎖定src檔案: 的確也會丟出AccessDeniedException,但會有被其它process使用中的訊息。
- 將測試案例分別丟於win7、win2012、win2016的機器上重複執行: 然而只有在發生問題的win10上會發生問題。
- retry: 透過retry的方式,在第二次就能成功移動檔案。
我在想會不會是JDK的bug,結果發現有人說: 可能是防毒軟體搞的鬼。於是我又做了以下實驗:
- 啟動測試程式,接著使用Win10內建的Windows Defender去掃描src的資料夾,最後發生沒有原因的AccessDeniedException。
- 將Win10內建的Windows Defender關掉,並在跑一次測試程式,發現能成功執行超過5千次。
這只是一個可能性,並不是絕對的。最後有幾種解決方式(workaround):
- 針對AccessDeniedException做retry,Apache Camel FileUtil使用此做法。
- 移動失敗改用複製,Guava使用此做法。
留言
張貼留言