在没有 O_SYNC 语义的 Java 中写入文件
writing a file in Java without O_SYNC semantics
在 C 中,当我调用 open()
打开文件描述符时,我必须显式传递 O_SYNC
标志以确保写入该文件的操作将在 write()
returns。如果我愿意,我可以 not 提供 O_SYNC
到 open()
,然后我的写入会 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.
在 C 中,当我调用 open()
打开文件描述符时,我必须显式传递 O_SYNC
标志以确保写入该文件的操作将在 write()
returns。如果我愿意,我可以 not 提供 O_SYNC
到 open()
,然后我的写入会 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.