10

I'm using RandomAccessFile in java:

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

How can I ensure that this data is flushed to the Operating System? There is no file.flush() method. (Note that I don't actually expect it to be physically written, I'm content with it being flushed to the operating system, so that the data will survive a tomcat crash but not necessarily an unexpected server power loss).

I'm using tomcat6 on Linux.

davmac
  • 20,150
  • 1
  • 40
  • 68
Tim Cooper
  • 10,023
  • 5
  • 61
  • 77
  • How can a `RandomAccessFile` be flushed only to OS not necessarily to physical disk? – Jin Kwon Jan 23 '16 at 01:28
  • 1
    The data is written to the disk cache pages, and therefore is immediately visible to other processes, and also will survive a crash of the process that wrote the data, but is not written to disk and therefore would not survive e.g. a sudden power loss. – Tim Cooper Jan 24 '16 at 19:22

6 Answers6

15

The only classes that provide a .flush() method are those that actually maintain their own buffers. As java.io.RandomAccessFile does not itself maintain a buffer, it does not need to be flushed.

Jonathan Callen
  • 11,301
  • 2
  • 23
  • 44
  • 3
    Jim Yingst says: "I should add that in my experience, RandomAccessFile is usually pretty slow for most applications. It's a jack-of-all-trades class; it does a lot of different things, but isn't particularly good at anyof them. You can usually create a combination of streams that does what you want with greater efficiency." – Tim Cooper Sep 28 '11 at 02:42
  • 1
    @TimCooper Your comment is for the OP, not this answer, right? – Jin Kwon Jan 23 '16 at 01:30
6

Have a look carefully at RandomAccessFile constructor javadoc:

The "rws" and "rwd" modes work much like the force(boolean) method of the FileChannel class, passing arguments of true and false, respectively, except that they always apply to every I/O operation and are therefore often more efficient. If the file resides on a local storage device then when an invocation of a method of this class returns it is guaranteed that all changes made to the file by that invocation will have been written to that device. This is useful for ensuring that critical information is not lost in the event of a system crash. If the file does not reside on a local device then no such guarantee is made.

Stas
  • 1,707
  • 15
  • 25
5

You can use getFD().sync() method.

KV Prajapati
  • 93,659
  • 19
  • 148
  • 186
  • The asker specifically stated they don't need the data physically written to disk, which is essentially what the sync() method is for. – davmac Sep 26 '11 at 03:22
  • @davmac I'd rather to ask you than ask to OP. How can a `RandomAccessFile` be flushed only to OS not necessarily to physical disk? – Jin Kwon Jan 23 '16 at 01:28
  • @JinKwon as per Jonathan Callen's answer - you don't need to flush a `RandomAccessFile`. Every time you write to it, the data you write is transferred to the OS immediately. – davmac Jan 23 '16 at 10:45
3

here's what i do in my app:

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

this is give 3-4times gain in performance compared to getFd().sync() and 5-7 times compared to "rws' mode

deoes exactly what the original question proposed: passes on unsaved data to the OS and out of JVM. Doesn't physically write to disk, and therefore introduces no annoying delays

dm4
  • 31
  • 1
  • 1
    If you simply delete those two lines, nothing will change, except that Java needs less garbage collection and the file system cache might become more efficient. – Steffen Heil Apr 13 '18 at 16:27
1

I reached here with the very same curiosity.

And I really can't figure what need to flush on OS and not necessarily need to flush to Disk part means.

In my opinion,

The best thing matches to the concept of a managed flushing is getFD().sync(), as @AVD said,

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

which looks like, by its documentation, it works very much like what FileChannel#force(boolean) does with true.

Now "rws" and "rwd" are look like they work as if specifying StandardOpenOption#SYNC and StandardOpenOption#DSYNC respectively while a FileChannel is open.

try(RandomAccessFile raw = new RandomAccessFile(file, "rws")) {
    raw.write...
    raw.write...
    raw.wirte...
    // don't worry be happy, woo~ hoo~ hoo~
}
Jin Kwon
  • 20,295
  • 14
  • 115
  • 184
-1

I learned that you can't..

Some related links here: http://www.cs.usfca.edu/~parrt/course/601/lectures/io.html and here: http://tutorials.jenkov.com/java-io/bufferedwriter.html

Caffeinated
  • 11,982
  • 40
  • 122
  • 216
  • 4
    (1) A `RandomAccessFile` is not an `OutputStream` or `Writer`, and thus can not be wrapped with a BufferedAnything. (2) The very goal is to *stop* buffering, not add it. – cHao Sep 26 '11 at 02:51
  • @cHao - Cool, thanks a lot. I'm heading back to the books then! – Caffeinated Sep 26 '11 at 02:53