I recommend using a BufferedOutputStream
wrapping a FileOutputStream
. I do not believe you will see any performance improvement by mucking with ByteBuffer
and FileChannel
, and that you'll be left with a lot of hard-to-maintain code if you go that route.
The reasoning is quite simple: regardless of the approach you take, the steps involved are the same:
- Generate bytes. You don't say how you plan to do this, and it could introduce an additional level of temporary buffering into the equation. But regardless, the Java data has to be turned into bytes.
- Accumulate bytes into a buffer. You want to buffer your data before writing it, so that you're not making lots of small writes. That's a given. But where that buffer lives is immaterial.
- Move bytes from Java heap to C heap, across JNI barrier. Writing a file is a native operation, and it doesn't read directly from the Java heap. So whether you buffer on the Java heap and then move the buffered bytes, or buffer in a direct
ByteBuffer
(and yes, you want a direct buffer), you're still moving the bytes. You will make more JNI calls with the ByteBuffer
, but that's a marginal cost.
- Invoke
fwrite
, a kernel call that copies bytes from the C heap into a kernel-maintained disk buffer.
- Write the kernel buffer to disk. This will outweigh all the other steps combined, because disks are slow.
There may be a few microseconds gained or lost depending on exactly how you implement these steps, but you can't change the basic steps.
The FileChannel
does give you the option to call force()
, to ensure that step #5 actually happens. This is likely to actually decrease your overall performance, as the underlying fsync
call will not return until the bytes are written. And if you really want to do it, you can always get the channel from the underlying stream.
Bottom line: I'm willing to bet that you're actually IO-bound, and there's no cure for that save better hardware.