2009-09-07 263 views
38

我需要編寫一個自定義批處理文件重命名。我已經完成了大部分工作,除非我無法弄清楚如何檢查文件是否已經打開。我只是使用java.io.File包,並且有一個canWrite()方法,但似乎沒有測試該文件是否正在被另一個程序使用。關於如何使這項工作的任何想法?檢查文件是否已經打開

+0

這是與平臺相關的。這是什麼平臺? – skaffman 2009-09-07 18:54:36

+0

Windows 2003服務器 – 2009-09-07 18:58:16

+0

剛剛重新簽署了您的問題,因爲您可能必須通過使用JNI或JNA調用WinAPI來執行此操作。 – 2009-09-07 19:14:33

回答

1

我不認爲你會得到一個明確的解決方案,操作系統不一定會告訴你,如果文件是否打開。

雖然javadoc載入警告,但您可能會從java.nio.channels.FileLock中獲得一些里程。

+0

是的,不能保證底層操作系統甚至文件系統都能以任何合理的方式支持文件鎖定。 – aperkins 2009-09-07 19:22:00

5

最好的辦法是在文件上設置獨佔鎖定。如果文件被其他進程打開,您將得到一個異常。例如,

File file = new File(fileName); 
FileChannel channel = new RandomAccessFile(file, "rw").getChannel(); 
// Get an exclusive lock on the whole file 
FileLock lock = channel.lock(); 
try { 
    lock = channel.tryLock(); 
    // Ok. You get the lock 
} catch (OverlappingFileLockException e) { 
    // File is open by someone else 
} finally { 
    lock.release(); 
} 
+2

乍一看這是一個不錯的主意,但是:我只是運行了修改了三個不同文件的代碼:使用UltraEdit打開的Word文件,Excel文件和文本文件。只有文本文件導致OverlappingFileLockException。前兩個在RandomAccessFile.open()中導致FileNotFoundException。您必須查看getMessage()以確定原因是文件被鎖定,這是不好的。當你認爲這條消息是由操作系統本地化的時候(在我的機器上是德語的),這很糟糕。 – 2009-09-07 19:38:18

+0

您可以使用file.exists()來避免鎖定未知資源。它看起來像只需要一個:lock()或tryLock()。 – 2009-09-07 20:43:54

+0

我同意serge_bg:在lock()之後執行tryLock()將引發OverlappingFileLockException。另外,lock.release()應該更高一級。最後,渠道本身也不需要關閉嗎? – 2011-10-25 14:55:11

12

(第q &一個是關於如何處理Windows的「打開文件」鎖......而不是如何實現這種可移植性鎖定。)

這整個問題是充滿了可移植性問題和競爭條件:

  • 您可以嘗試使用FileLock,但它不一定支持您的操作系統和/或文件系統。
  • 看來,在Windows上,如果另一個應用程序以特定方式打開文件,則可能無法使用FileLock。
  • 即使您設法使用FileLock或其他東西,仍然存在可能會出現問題,並在測試文件和執行重命名之間打開文件的問題。

更簡單和(可能)更強大的解決方案是隻是嘗試重命名(或者不管它是你正在嘗試做的)和診斷的返回值和/或由於打開的文件中出現的任何Java異常。

注:

  1. 如果使用Files API,而不是File API,你會得到一個失敗的事件的詳細信息。

  2. 在允許您重命名(或其他)鎖定或打開的文件的系統上,您不會得到任何失敗結果或異常。該操作將會成功。

+0

我可能是錯的,但我相信一些(不是很奇特)的文件系統,你甚至可以在文件被寫入的時候移動文件 – 2013-05-05 14:30:31

+0

@JaroslavZáruba - 這與問題有什麼關係或者我的答案? – 2013-05-05 14:41:33

+0

「嘗試重命名...並診斷任何Java異常」 - 這遠非強健,在典型的Linux FS上,您不會得到任何異常eption – 2013-05-05 17:13:50

21

使用Apache下議院IO庫...

boolean isFileUnlocked = false; 
try { 
    org.apache.commons.io.FileUtils.touch(yourFile); 
    isFileUnlocked = true; 
} catch (IOException e) { 
    isFileUnlocked = false; 
} 

if(isFileUnlocked){ 
    // Do stuff you need to do with a file that is NOT locked. 
} else { 
    // Do stuff you need to do with a file that IS locked 
} 
+0

這不會爲.xls文件引發任何異常,只需觸及它即可。 – WillBD 2014-09-02 12:46:22

+11

比賽狀況提醒! – 2014-10-21 22:24:01

+0

這將更改文件的上次修改日期和時間。 – ssp 2016-11-08 17:19:34

4
// TO CHECK WHETHER A FILE IS OPENED 
    // OR NOT (not for .txt files) 

    // the file we want to check 
    String fileName = "C:\\Text.xlsx"; 
    File file = new File(fileName); 

    // try to rename the file with the same name 
    File sameFileName = new File(fileName); 

    if(file.renameTo(sameFileName)){ 
     // if the file is renamed 
     System.out.println("file is closed");  
    }else{ 
     // if the file didnt accept the renaming operation 
     System.out.println("file is opened"); 
    } 
+1

簡直就是天才! +1。 – 2017-02-16 12:41:50

+2

不適用於Linux。在POSIX文件系統中,文件名不是主鍵,而是鏈接到文件內容。所以你可以重新命名或刪除打開的文件。沒有人得到任何錯誤。 – 2017-04-01 15:30:01

+2

可以確認這適用於Windows10。看起來比挑起異常更優雅。使用ext4不能在linux上運行。 – JosefScript 2017-04-13 07:45:30

-3

如果文件正在使用FileOutputStream fileOutputStream = new FileOutputStream(file);返回java.io.FileNotFoundException用「的過程,因爲它是爲無法訪問文件在異常消息中由另一個進程使用「。

+0

如果文件沒有被使用,那麼用0字節覆蓋文件的內容,因此它基本上刪除了文件,我將不勝感激。 – Aikerima 2017-04-05 11:39:56

+0

適用於linux(ext4)和Win10。第三次downvote是我的。 – JosefScript 2017-04-13 07:41:54

+0

我有這個異常,當我使用_FileOutputStream fileOutputStream =新FileOutputStream(文件)_ – 2017-09-02 15:19:58

2

org.apache.commons.io.FileUtils.touch(yourFile)不檢查您的文件是否打開。相反,它會將文件的時間戳更改爲當前時間。

我用IOException異常,它工作得很好:

try 
{ 
    String filePath = "C:\sheet.xlsx"; 
    FileWriter fw = new FileWriter(filePath);     
} 
catch (IOException e) 
{ 
    System.out.println("File is open"); 
} 
+0

正常控制流的異常使用被認爲是一種不好的做法。另外,在沒有產生異常的情況下,你最終可能會打開'fw'。 – 2017-08-30 21:51:36

+0

因爲我最終可以使用,所以文件將以任何方式關閉 FileWriter fw; 嘗試 { String filePath =「C:\ sheet.xlsx」; fw = new FileWriter(filePath); } catch(IOException e) { System.out.println(「File is open」); } finally { fw.close(); } – Ali 2017-09-13 19:59:12