2009-01-06 35 views
11

這可能類似於以前的帖子,但我想具體說明在網絡上使用鎖定而不是本地鎖定。我想寫一個文件到共享的位置,所以它可能會在網絡上(當然是Windows網絡,也許是Mac)。我想阻止其他人在寫它的同時閱讀這個文件的任何部分。這不會是一個高度併發的進程,文件通常不會超過10MB。網絡上的Java文件鎖定

我已閱讀FileLock文檔和File文檔,並且對於什麼是安全的和什麼是不安全的有些困惑。我想鎖定整個文件,而不是部分文件。

我可以使用FileChannel.tryLock(),它在網絡上是否安全,還是取決於網絡類型?它是否可以在標準的Windows網絡上運行(如果有這樣的事情)。

如果這不起作用,創建零字節文件或目錄作爲鎖定文件,然後寫出主文件是最好的。爲什麼File.createNewFile()文檔說不要使用這個文件鎖定?我很欣賞這受到比賽條件的限制,並不理想。

回答

5

這在網絡文件系統上無法可靠地完成。只要您的應用程序是訪問文件的唯一應用程序,最好實施某種協作鎖定過程(可能會在打開文件時將鎖定文件寫入網絡文件系統)。然而,不建議這樣做的原因是,如果您的進程崩潰或網絡故障或其他任何問題發生,您的應用程序會進入惡劣的骯髒狀態。

3

您可以在要寫入的服務器上放置一個空文件。

當你想寫服務器,你可以捕獲令牌。只有當你有令牌時,你才應該寫入服務器上的任何文件。

當您準備好文件操作或引發異常時,您必須釋放令牌。

助手類可以像

private FileLock lock; 

private File tokenFile; 

public SLTokenLock(String serverDirectory) { 
    String tokenFilePath = serverDirectory + File.separator + TOKEN_FILE; 
    tokenFile = new File(tokenFilePath); 
} 

public void catchCommitToken() throws TokenException { 
    RandomAccessFile raf; 
    try { 
     raf = new RandomAccessFile(tokenFile, "rw"); //$NON-NLS-1$ 
     FileChannel channel = raf.getChannel(); 
     lock = channel.tryLock(); 

     if (lock == null) { 
      throw new TokenException(CANT_CATCH_TOKEN); 
     } 
    } catch (Exception e) { 
     throw new TokenException(CANT_CATCH_TOKEN, e); 
    } 
} 

public void releaseCommitToken() throws TokenException { 
    try { 
     if (lock != null && lock.isValid()) { 
      lock.release(); 
     } 
    } catch (Exception e) { 
     throw new TokenException(CANT_RELEASE_TOKEN, e); 
    } 
} 

你的操作,那麼應該看起來像

try { 
     token.catchCommitToken(); 

     // WRITE or READ to files inside the directory 
    } finally { 
     token.releaseCommitToken(); 
    } 
1

而不是實施鎖定策略,將在所有的可能性,依靠讀者要堅持你的約定,但不會強迫他們,也許你可以將文件寫出到一個隱藏的或模糊的命名文件中,這樣讀者將無法看到它。寫入操作完成後,將該文件重命名爲預期的公用名。

缺點是隱藏和/或重命名沒有額外的IO可能需要您使用本機操作系統命令,但這樣做的過程應該是相當簡單和確定性的。

4

我發現這個錯誤報告,它描述了爲什麼關於文件鎖定的註釋被添加到File.createNewFile文檔。

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4676183

它指出:

如果前將文件標記爲deleteOnExit 調用createNewFile但該文件已經存在,您運行刪除你沒有創建一個文件的風險,放棄某人鎖定!另一方面,如果在創建之後標記文件,則會失去原子性:如果程序在文件被標記之前退出,它將不會被刪除,並且鎖定將被「楔住」。

所以它看起來像主要原因鎖定與File.createNewFile氣餒()是你可以用孤立的鎖定文件結束了,如果你有機會來刪除它之前的JVM意外終止。如果你可以處理孤立的鎖文件,那麼它可以用作一個簡單的鎖定機制。但是,我不會推薦bug報告的評論中提出的方法,因爲它具有讀取/寫入時間戳值和回收已過期的鎖的爭用條件。