FileChannel#force and buffering
Asked Answered
T

1

9

I would like to make it clear and draw some parallels between FileOutputStream and FileChannel right now.

So first of all, it seems like the most efficient way to write file with standart Java io is to use FileOutputStream which is wrapped with BufferedOutputStream. Because it automatically flushes, when the internal buffer is overflowed. It is convenient to be able to do single writes (single bytes, floats, etc.) as well as array ones and to be not worried about speed. The only thing you should never forget is to close it (to perform the final flush). Benefits of using BufferedOutputStream wrapper are evident and must have for everyone (I hope).

Now about FileChannel. FileChannel has force method, which is an equivalent to flush in FileOutputStream, isn't it? And javadocs clearly say, that you should use it to be sure that your changes have been made to the target file. But, I don't understand when and why should I use it, if there is no "BufferedFileChannel" wrapper. In other words, where is buffering for FileChannel? Is it automatic and hidden in FileChannel itself like in BufferedOutputStream? If not, then why on earth would I need force method, since there is nothing to force (all changes are already applied to file after using write method) and do I have to implement buffering by myself?

Tardif answered 20/1, 2011 at 1:13 Comment(0)
F
13

BufferedOutputStream have a cache in java, which FileChannel do not.

However, FileChannel do have OS-Level cache. In which .force() is the same as fsync / fdatasync.

In OpenJDK 6 src/solaris/native/sun/nio/ch/FileChannelImpl.c

  157 JNIEXPORT jint JNICALL
  158 Java_sun_nio_ch_FileChannelImpl_force0(JNIEnv *env, jobject this,
  159                                        jobject fdo, jboolean md)
  160 {
  161     jint fd = fdval(env, fdo);
  162     int result = 0;
  163 
  164     if (md == JNI_FALSE) {
  165         result = fdatasync(fd);
  166     } else {
  167         result = fsync(fd);
  168     }
  169     return handle(env, result, "Force failed");
  170 }

Read this blog if you want to know more how OS works in this level.

Foah answered 20/1, 2011 at 2:12 Comment(4)
So there is no reason to make additional buffering on java level for FileChannel? I. e. what if I will use just a ByteBuffer 64K-256K and just fill it with needed information until it is overflowed and then throw it into FileChannel#write? Is this solution the best using FileChannel?Tardif
@Haroogan, (1) each write to FileChannel is a syscall - this involve some OS-level overhead; (2) buffer in java-level is more predictable and tunable; (3) a write of 4KB (aligned) block often give the best performance; (4) do your own benchmarkFoah
@J-16SDiZ Do we always have to call FileChannel#force?Thornburg
FileChannel does not have an OS-level cache. The operating system does, and it does that for every open file. Or not. Nothing to do with FileChannel specifically whatsoever.Globeflower

© 2022 - 2024 — McMap. All rights reserved.