在没有 O_SYNC 语义的 Java 中写入文件

writing a file in Java without O_SYNC semantics

在 C 中,当我调用 open() 打开文件描述符时,我必须显式传递 O_SYNC 标志以确保写入该文件的操作将在 write() returns。如果我愿意,我可以 not 提供 O_SYNCopen(),然后我的写入会 return 快得多,因为它们只需要在 returning 之前将其放入文件系统缓存中。如果我愿意,稍后我可以通过调用 fsync() 强制将对此文件的所有未完成写入写入磁盘,这将阻塞直到该操作完成。 (有关所有这些的更多详细信息,请参见 Linux man page。)

在 Java 中有什么方法可以做到这一点吗?我能找到的最相似的事情是使用 BufferedOutputStream 并在其上调用 .flush(),但是如果我正在写入随机文件偏移量,我相信这意味着输出流的内部缓冲区可能会结束消耗大量内存。

根据 Sergey Tachenov 的评论,我发现您可以为此使用 FileChannel。这是一些我认为可以解决问题的示例代码:

import java.nio.*;
import java.nio.channels.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.io.*;
import java.util.*;
import java.util.concurrent.*;

import static java.nio.file.StandardOpenOption.*;

public class Main {
    public static void main(String[] args) throws Exception {

        // Open the file as a FileChannel.
        Set<OpenOption> options = new HashSet<>();
        options.add(WRITE);
        // options.add(SYNC);     <------- This would force O_SYNC semantics.
        try (FileChannel channel = FileChannel.open(Paths.get("./test.txt"), options)) {

            // Generate a bit data to write.
            ByteBuffer buffer = ByteBuffer.allocate(4096);
            for (int i = 0; i < 10; i++) {
                buffer.put(i, (byte) i);
            }

            // Choose a random offset between 0 and 1023 and write to it.
            long offset = ThreadLocalRandom.current().nextLong(0, 1024);
            channel.write(buffer, offset);
        }
    }
}

使用Java 7 NIO FileChannel#force方法:

RandomAccessFile aFile = new RandomAccessFile("file.txt", "rw");
FileChannel inChannel = aFile.getChannel();
// .....................
// flushes all unwritten data from the channel to the disk
channel.force(true);

一个重要的细节:

If the file does not reside on a local device then no such guarantee is made.