2009-01-06 78 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报告的评论中提出的方法,因为它具有读取/写入时间戳值和回收已过期的锁的争用条件。