3

我有一组文件。该文件集在 NTFS 共享上是只读的,因此可以有许多阅读器。每个文件由一个具有写访问权限的写入者偶尔更新。

我如何确保:

  1. 如果写入失败,则表示之前的文件仍然可读
  2. 读者无法支撑单个作者

我正在使用 Java,我目前的解决方案是让作者写入一个临时文件,然后使用File.renameTo(). 问题出在 NTFS 上,renameTo如果目标文件已经存在则失败,因此您必须自己删除它。但是如果作者删除目标文件然后失败(计算机崩溃),我没有可读的文件。

nio 的 FileLock 只适用于同一个 JVM,所以对我来说没用。

如何使用 Java 安全地更新具有多个阅读器的文件?

4

6 回答 6

3

根据JavaDoc

此文件锁定 API 旨在直接映射到底层操作系统的本机锁定设施。因此,文件上的锁应该对所有有权访问该文件的程序可见,而不管这些程序是用什么语言编写的。

于 2009-01-07T18:15:42.460 回答
1

我不知道这是否适用,但如果您在纯 Vista/Windows Server 2008 解决方案中运行,我会使用 TxF(事务性 NTFS),然后确保您打开文件句柄并通过调用通过 JNI 提供适当的文件 API。

如果这不是一个选项,那么我认为您需要某种服务,所有客户端都可以访问该服务,该服务负责协调文件的读/写。

于 2009-01-07T18:12:52.090 回答
1

在 Unix 系统上,我会删除该文件,然后打开它进行写入。任何打开它以供阅读的人仍然会看到旧的,一旦他们全部关闭它,它就会从文件系统中消失。我不知道 NTFS 是否具有类似的语义,尽管我听说它基于 BSD 的文件系统而失败,所以也许它确实如此。

于 2009-01-07T18:17:17.683 回答
1

无论什么操作系统等,应该始终有效的东西正在改变您的客户端软件。

如果这是一个选项,那么你可以有一个文件“settings1.ini”,如果你想改变它,你创建一个文件“settings2.ini.wait”,然后把你的东西写进去,然后把它重命名为“settings2” .ini”,然后删除“settings1.ini”。

如果您更改的客户端软件最后读取了 settings1.ini,则它只会检查 settings2.ini,反之亦然。

这样你总是有一个工作副本。

于 2009-01-07T19:29:26.663 回答
0

可能不需要锁定。我对 Windows 上的 FS API 不太熟悉,但由于 NTFS 支持硬链接和软链接,AFAIK,如果你的设置允许,你可以试试这个:

使用硬链接或软链接指向实际文件,并以不同的方式命名文件。让每个人都可以使用链接的名称访问文件。

在同一文件夹中以不同的名称写入新文件。

完成后,让文件指向新文件。最佳情况下,Windows 将允许您通过在一个原子操作中替换现有链接来创建新链接。然后,您将有效地让链接始终识别有效文件,无论是旧文件还是新文件。在最坏的情况下,您必须先删除旧文件,然后创建指向新文件的链接。在这种情况下,程序将在短时间内无法找到该文件。(另外,Mac OS X 提供了一个“ExchangeObjects”功能,允许您以原子方式交换两个项目——也许 Windows 提供类似的东西)。

这样,任何已打开旧文件的程序都将继续访问旧文件,而您不会进入创建新文件的过程。只有当应用程序注意到新版本的存在时,它才能关闭当前并再次打开它,这样才能访问新版本。

但是,我不知道如何在 Java 中创建链接。也许您必须为此使用一些本机 API。

我希望这无论如何都会有所帮助。

于 2009-01-07T18:26:35.667 回答
-1

我最近一直在处理类似的事情。如果您正在运行 Java 5,也许您可​​以考虑将 NIO 文件锁与 ReentrantReadWriteLock 结合使用?确保所有引用 FileChannel 对象的代码也引用 ReentrantReadWriteLock。这样,NIO 将其锁定在每个 VM 级别,而可重入锁将其锁定在每个线程级别。

FileLock fileLock = filechannel.lock(position, size, shared);
reentrantReadWriteLock.lock();

// do stuff

fileLock.release();
reentrantReadWriteLock.unlock();

当然,需要一些异常处理。

于 2009-01-07T18:19:15.587 回答