如何安全地更新具有多个读者和一个作者的文件?

发布于 2024-07-11 13:26:39 字数 420 浏览 8 评论 0原文

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

如何确保:

  1. 如果写入失败,前一个文件仍然可读
  2. 读者无法支持单个写入器

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

nio 的 FileLock 只能在同一个 JVM 上工作,所以对我来说没用。

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

I have a set of files. The set of files is read-only off a NTFS share, thus can have many readers. Each file is updated occasionally by one writer that has write access.

How do I ensure that:

  1. If the write fails, that the previous file is still readable
  2. Readers cannot hold up the single writer

I am using Java and my current solution is for the writer to write to a temporary file, then swap it out with the existing file using File.renameTo(). The problem is on NTFS, renameTo fails if target file already exists, so you have to delete it yourself. But if the writer deletes the target file and then fails (computer crash), I don't have a readable file.

nio's FileLock only work with the same JVM, so it useless to me.

How do I safely update a file with many readers using Java?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

厌倦 2024-07-18 13:26:39

根据 JavaDoc

此文件锁定 API 旨在
直接映射到本机锁定
底层运营设施
系统。 因此,文件上持有的锁
应该对所有程序可见
有权访问该文件,无论
这些程序所使用的语言
已写。

According to the JavaDoc:

This file-locking API is intended to
map directly to the native locking
facility of the underlying operating
system. Thus the locks held on a file
should be visible to all programs that
have access to the file, regardless of
the language in which those programs
are written.

酒几许 2024-07-18 13:26:39

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

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

I don't know if this is applicable, but if you are running in a pure Vista/Windows Server 2008 solution, I would use TxF (transactional NTFS) and then make sure you open the file handle and perform the file operations by calling the appropriate file APIs through JNI.

If that is not an option, then I think you need to have some sort of service that all clients access which is responsible to coordinate the reading/writing of the file.

可爱咩 2024-07-18 13:26:39

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

On a Unix system, I'd remove the file and then open it for writing. Anybody who had it open for reading would still see the old one, and once they'd all closed it it would vanish from the file system. I don't know if NTFS has similar semantics, although I've heard that it's losely based on BSD's file system so maybe it does.

我不会写诗 2024-07-18 13:26:39

无论什么操作系统等,应该始终有效的事情是更改您的客户端软件。

如果这是一个选项,那么您可以有一个文件“settings1.ini”,如果您想更改它,您可以创建一个文件“settings2.ini.wait”,然后将您的内容写入其中,然后将其重命名为“settings2” .ini”,然后删除“settings1.ini”。

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

这样您就始终拥有一份工作副本。

Something that should always work, no matter what OS etc, is changing your client software.

If this is an option, then you could have a file "settings1.ini" and if you want to change it, you create a file "settings2.ini.wait", then write your stuff to it and then rename it to "settings2.ini" and then delete "settings1.ini".

Your changed client software would simply always check for settings2.ini if it has read settings1.ini last, and vice versa.

This way you have always a working copy.

夜夜流光相皎洁 2024-07-18 13:26:39

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

使用硬链接或软链接指向实际文件和名称文件不同。 让每个人都可以使用链接名称访问该文件。

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

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

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

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

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

There might be no need for locking. I am not too familiar with the FS API on Windows, but as NTFS supports both hard links and soft links, AFAIK, you can try this if your setup allows it:

Use a hard or soft link to point to the actual file, and name the file diferently. Let everyone access the file using the link's name.

Write the new file under a different name, in the same folder.

Once it is finished, have the file point to the new file. Optimally, Windows would allow you to create the new link with replacing the existing link in one atomic operation. Then you'd effectively have the link always identify a valid file, either the old or the new one. At worst, you'd have to delete the old one first, then create the link to the new file. In that case, there'd be a short time span in which a program would not be able to locate the file. (Also, Mac OS X offers a "ExchangeObjects" function that allows you to swap two items atomically - maybe Windows offers something similar).

This way, any program that has the old file already opened will continue to access the old one, and you won't get into its way creating the new one. Only if an app then notices the existence of the new version, it could then close the current and open it again, this way getting access to the new version.

I don't know, however, how to create links in Java. Maybe you have to use some native API for that.

I hope this helps anyways.

不忘初心 2024-07-18 13:26:39

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

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

// do stuff

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

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

I have been dealing with something similar recently. If you are running Java 5, perhaps you could consider using NIO file locks in conjunction with a ReentrantReadWriteLock? Make sure all code referencing the FileChannel object ALSO references the ReentrantReadWriteLock. This way the NIO locks it at a per-VM level while the reentrant lock locks it at a per-thread level.

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

// do stuff

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

Of course, some exception handling would be required.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文