如何安全地更新包含许多读者和一个作者的文件?

时间:2009-01-07 18:08:20

标签: java concurrency filesystems ntfs atomic

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

我如何确保:

  1. 如果写入失败,则前一个文件仍然可读
  2. 读者无法阻止单一作家
  3. 我正在使用Java,我当前的解决方案是让编写者写入临时文件,然后使用File.renameTo()将其与现有文件交换出来。问题出在NTFS上,如果目标文件已经存在,renameTo会失败,所以你必须自己删除它。但是如果编写器删除目标文件然后失败(计算机崩溃),我没有可读文件。

    nio的FileLock只能使用相同的JVM,所以对我来说没用。

    如何使用Java安全地更新许多读者的文件?

6 个答案:

答案 0 :(得分:3)

根据JavaDoc

  

此文件锁定API旨在   直接映射到本机锁定   基础经营的设施   系统。因此锁定在文件上   应该对所有程序都可见   无论如何都可以访问该文件   这些程序的语言   写的。

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

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

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

您更改的客户端软件只会检查settings2.ini是否已读取settings1.ini,反之亦然。

这样你就可以随时使用。

答案 4 :(得分:0)

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

使用硬链接或软链接指向实际文件,并且不同地命名文件。让每个人都使用链接名称访问该文件。

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

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

这样,任何已经打开旧文件的程序都将继续访问旧文件,您将无法创建新文件。只有当应用程序注意到新版本的存在时,它才会关闭当前并再次打开它,这样就可以访问新版本了。

但是,我不知道如何在Java中创建链接。也许你必须使用一些原生API。

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

答案 5 :(得分:-1)

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

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

// do stuff

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

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