问题 Java文件锁定在网络上


这可能与以前的帖子类似,但我想具体说明在网络上使用锁定,而不是在本地。我想将文件写入共享位置,因此它可能会进入网络(当然是Windows网络,也许是Mac)。我希望阻止其他人在撰写文件时阅读该文件的任何部分。这不是一个高度并发的过程,文件通常小于10MB。

我读过了 FileLock 文档和 File 文档,我有点困惑,关于什么是安全的,什么是不安全的。我想锁定整个文件,而不是部分文件。

我可以用吗 FileChannel.tryLock(),它在网络上是安全的,还是取决于网络的类型?它是否适用于标准的Windows网络(如果有这样的话)。

如果这不起作用,最好将零字节文件或目录创建为锁定文件,然后写出主文件。为什么这样 File.createNewFile() 文档说不要用它来进行文件锁定?我很欣赏这是受比赛条件限制的,并不理想。


8740
2018-01-06 12:08


起源



答案:


这在网络文件系统上无法可靠地完成。只要您的应用程序是访问该文件的唯一应用程序,最好实现某种协作锁定过程(可能在打开文件时将锁定文件写入网络文件系统)。但是,不建议使用的原因是,如果您的进程崩溃或网络出现故障或发生任何其他问题,您的应用程序将陷入令人讨厌的脏状态。


6
2018-01-06 12:27





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

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

它指出:

如果将文件标记为deleteOnExit 之前 调用createNewFile但文件已经存在,你冒着删除你没有创建的文件的风险,并且丢掉别人的锁!另一方面,如果您标记文件  创建它,你失去原子性:如果程序在标记文件之前退出,它将不会被删除,锁定将被“楔入”。

因此,看起来不推荐使用File.createNewFile()阻止锁定的主要原因是,如果JVM在您有机会删除它之前意外终止,您最终可能会遇到孤立的锁定文件。如果你可以处理孤立的锁文件,那么它可以用作一个简单的锁定机制。但是,我不建议在错误报告的注释中建议的方法,因为它具有围绕读/写时间戳值和回收过期锁的竞争条件。


4
2017-10-19 21:23





您可以在要写入的服务器上放置一个空文件。

当您想要写入服务器时,您可以捕获令牌。只有拥有令牌时,才应写入服务器上的任何文件。

当您准备好文件操作或抛出异常时,您必须释放令牌。

帮助程序类可以看起来像

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();
    }

3
2018-01-06 12:30





而不是实现一种锁定策略,它很可能依赖于读者遵守您的约定而不会强迫它们,也许您可​​以将文件写入隐藏或模糊命名的文件中,其中读者将无法看到该文件。写入操作完成后,将文件重命名为预期的公共名称。

缺点是在没有额外IO的情况下隐藏和/或重命名可能需要您使用本机OS命令,但执行此操作的过程应该相当简单且具有确定性。


1
2018-01-06 14:43