如何刷新 RandomAccessFile(Java)?

10

我正在使用Java中的RandomAccessFile:

file = new RandomAccessFile(filename, "rw");
...
file.writeBytes(...);

如何确保这些数据被刷新到操作系统?没有file.flush()方法。(请注意,我并不希望它实际被写入,我只需要它被刷新到操作系统,以便数据可以在Tomcat崩溃后存活,但不一定能经受住意外的服务器断电)。

我正在使用Linux上的tomcat6。


一个RandomAccessFile如何只刷新到操作系统而不一定刷新到物理磁盘? - Jin Kwon
1
数据被写入磁盘缓存页面,因此立即对其他进程可见,并且在编写数据的进程崩溃时也将幸存,但不会被写入磁盘,因此不能幸免于例如突然断电等情况。 - Tim Cooper
6个回答

15

只有那些维护其自己的缓冲区的类提供.flush()方法。由于java.io.RandomAccessFile本身不维护缓冲区,因此它不需要刷新。


3
Jim Yingst说:“我要补充的是,根据我的经验,RandomAccessFile对于大多数应用程序来说通常都很慢。它是一个全能型类;它可以做很多不同的事情,但在任何一件事上都不是特别出色。你通常可以创建一组流来更有效地完成你想要的功能。” - Tim Cooper
1
@TimCooper 你的评论是针对楼主,而不是这个答案,对吗? - Jin Kwon

6
仔细查看RandomAccessFile构造函数的javadoc:
“rws”和“rwd”模式的工作方式与FileChannel类的force(boolean)方法类似,分别传递true和false参数,但它们始终应用于每个I/O操作,并且因此通常更有效。如果文件驻留在本地存储设备上,则当此类的方法调用返回时,保证该调用对文件所做的所有更改都已写入该设备。这对于确保在系统崩溃时不会丢失关键信息非常有用。如果文件不驻留在本地设备上,则不提供此类保证。

恕我直言,你的意思是什么?你是说任何人都应该使用 "rws" 或 "rwd" 来保证刷新吗?那 "rw" 是什么用的? - Jin Kwon
@JinKwon 读取 写入 - Erwin Bolwidt

5
您可以使用getFD().sync()方法。

提问者明确表示他们不需要将数据物理写入磁盘,这基本上就是sync()方法的作用。 - davmac
@davmac,我宁愿问你也不问OP。如何将RandomAccessFile刷新到操作系统而不一定刷新到物理磁盘? - Jin Kwon
根据Jonathan Callen的回答,@JinKwon不需要刷新RandomAccessFile。每次写入数据时,您写入的数据会立即传输到操作系统。 - davmac

3

以下是我的应用中所做的:

rf.close();
rf = new RandomAccessFile("mydata", "rw");

这将比getFd().sync()提高3-4倍的性能,并且比“rws”模式快5-7倍。
与原始问题提出的一样,它确切地执行了操作:将未保存的数据传递给操作系统并离开JVM。不会物理写入磁盘,因此不会引入任何烦人的延迟。

1
如果你只是删除这两行代码,除了Java需要更少的垃圾回收和文件系统缓存可能会变得更加高效之外,什么都不会改变。 - Steffen Heil

1

我也怀着同样的好奇心来到这里。

但我真的无法理解需要在操作系统上刷新,而不一定需要刷新到磁盘的部分是什么意思。

在我看来,

最符合托管刷新概念的事情是getFD().sync(),就像@AVD所说的那样。

try(RandomAccessFile raw = new RandomAccessFile(file, "rw")) {
    raw.write...
    raw.write...
    raw.getFD().sync();
    raw.wirte...
}

根据文档,这个看起来很像 FileChannel#force(boolean) 使用 true 的工作方式。

现在,"rws""rwd" 看起来就像是在一个 FileChannelopen时分别指定了 StandardOpenOption#SYNCStandardOpenOption#DSYNC

try(RandomAccessFile raw = new RandomAccessFile(file, "rws")) {
    raw.write...
    raw.write...
    raw.wirte...
    // don't worry be happy, woo~ hoo~ hoo~
}

-1

4
(1) RandomAccessFile 不是一个 OutputStream 或者 Writer,因此不能被包装成一个 BufferedAnything。 (2) 目标正是停止缓冲,而不是加入缓冲。 - cHao
@cHao - 很酷,非常感谢。那我就回去看书了! - Caffeinated

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