如何使用AsynchronousFileChannel异步强制写入文件

5

你能告诉我们更多关于你的问题吗?目前我无法理解“异步力”的意义。也许,使用SYNCDSYNC选项打开你的文件是你正在寻找的。 - mkrakhin
如果你想要“强制”写入,它就不能是异步的——这两个概念是矛盾的。你可以选择强制写入,或者只是在通道上使用普通的异步写入。 - kaykay
@kaykay:这绝对不矛盾,否则就不会有标准 C 库函数来执行这个操作:http://pubs.opengroup.org/onlinepubs/009695399/functions/aio_fsync.html。只是在 Java 中我目前找不到相应的函数。 - Chris Leishman
@artbristol:只有在回调/事件发生时,数据已被强制存储的保证才是真实的。这与异步写入非常相似:您请求进行写入,但在发出回调之前没有保证它已经完成。 - Chris Leishman
@kaykay - 实际上异步force()比异步write()更有意义,因为写入是快速的,并且通常只将数据复制到内核缓冲区,而force()可能会阻塞很长时间,直到数据被写入物理存储。在完全异步的应用程序堆栈中,例如基于Netty,您不允许在事件循环中执行长时间阻塞的操作。在这种情况下,我被迫使用JNA通过asio_fsync(尚未尝试)或使用单独的线程池来处理force()调用。 - Piotr Kołaczkowski
显示剩余2条评论
1个回答

0

我有一些代码,在其中向一个文件发送了大量的写操作,大部分都是以fire-and-forget模式进行的。偶尔,我想要刷新对磁盘的更改,仅仅是为了给用户一些信心,即使断电,他们也不会失去所有数据。为此,我有时会这样做:

channel.write(ByteBuffer.wrap(new byte[0]), 0, null, new CompletionHandler<Integer, Object>() {
    @Override
    public void completed(Integer result, Object attachment) {
        try {
            channel.force(false);
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }

    @Override
    public void failed(Throwable exc, Object attachment) {
        try {
            channel.force(false);
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }
});

这似乎会导致磁盘上的更改得到反映,并且不会阻塞调用线程。当然,它会阻塞通道线程池中的一个线程,从而在一段时间内防止其他写入完成。

它还有一个缺点,即CompletionHandler的方法不能抛出异常,因此需要使用try-catch块。对于我的应用程序,绝对确保force已完成并不是必需的,因此这不是问题。


正如您所指出的那样,这并没有解决问题,因为它仍然会阻塞通道线程池中的一个线程。Java 没有办法调用 flush 并提供回调以表示完成,这仍然很奇怪。我很想知道是否有充分的理由或者这是一个疏忽。 - Chris Leishman

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