Windows上移動檔案發生非預期的AccessDeniedException

我們有個功能會透過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。

我做過以下推測與實驗:

  • 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使用此做法。