Java网络文件锁定

12

这与以前的帖子可能类似,但我想具体说明在网络上锁定的用法,而不是本地锁定。我想要将文件写入共享位置,因此它很可能会在网络上传输(肯定是Windows网络,也许是Mac网络)。我想要防止其他人在文件正在被写入时读取文件的任何部分。这不会是高并发过程,文件通常不超过10MB。

我已经阅读了FileLock文档和File文档,并感到有些困惑,不知什么是安全的,什么不是安全的。 我想锁定整个文件,而不是其中的一部分。

我能否使用FileChannel.tryLock(),并且在网络上安全,还是取决于网络类型?它在标准的Windows网络中有效吗(如果有这样的东西)。

如果这样不行,是否最好创建一个零字节的文件或目录作为锁文件,然后再编写主文件。为什么File.createNewFile()文档说不要用它来进行文件锁定?我知道这存在竞态条件,也不是理想的。

4个回答

8

在网络文件系统上,这种操作不可靠。只要您的应用程序是访问该文件的唯一应用程序,最好实现某种协作锁定过程(例如,在打开文件时将锁定文件写入网络文件系统)。然而,不建议这样做的原因是,如果您的进程崩溃或网络出现故障或发生任何其他问题,您的应用程序会陷入一个不良、肮脏的状态。


4
我找到了这个错误报告,它描述了为什么在File.createNewFile文档中添加了有关文件锁定的注释。

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

它说:
如果在调用createNewFile之前将文件标记为deleteOnExit,但文件已经存在,则存在删除未创建的文件和删除他人锁定的风险!另一方面,如果在创建文件后标记该文件,则会失去原子性:如果程序在文件被标记之前退出,则不会被删除且锁将被“卡住”。
因此,似乎不鼓励使用File.createNewFile()进行锁定的主要原因是,如果JVM在您有机会删除它之前意外终止,则可能会出现孤立的锁定文件。如果您可以处理孤立的锁定文件,则可以将其用作简单的锁定机制。但是,我不建议在错误报告的评论中建议的方法,因为它在读/写时间戳值和回收过期锁定时存在竞争条件。

4
你可以在服务器上拥有一个空文件,以便你想要写入时捕获令牌。只有当你拥有令牌时,才应该写入任何位于服务器上的文件。
当你完成文件操作或抛出异常时,必须释放令牌。辅助类可以如下所示:
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可能需要您使用本机操作系统命令,但执行此操作的过程应该相当简单和确定性的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接