FileChannel#force и буферизация

Я хотел бы прояснить ситуацию и прямо сейчас провести некоторые параллели между FileOutputStream и FileChannel.

Итак, прежде всего, похоже, что наиболее эффективным способом записи файла со стандартным вводом-выводом Java является использование FileOutputStream, который обернут BufferedOutputStream. Потому что он автоматически сбрасывается, когда внутренний буфер переполняется. Удобно иметь возможность делать одиночные записи (одиночные байты, числа с плавающей запятой и т. д.), а также записи массивов и не беспокоиться о скорости. Единственное, что вы никогда не должны забывать, это закрыть его (выполнить финальную промывку). Преимущества использования оболочки BufferedOutputStream очевидны и должны быть у всех (надеюсь).

Теперь о FileChannel. FileChannel имеет метод force, который эквивалентен flush в FileOutputStream, не так ли? И в javadocs ясно сказано, что вы должны использовать его, чтобы убедиться, что ваши изменения были внесены в целевой файл. Но я не понимаю, когда и зачем его использовать, если нет обертки BufferedFileChannel. Другими словами, где находится буферизация для FileChannel? Является ли он автоматическим и скрытым в самом FileChannel, как в BufferedOutputStream? Если нет, то с какой стати мне нужен принудительный метод, если нечего принудительно применять (все изменения уже применяются к файлу после использования метода записи) и я должен сам реализовывать буферизацию?


person Alexander Shukaev    schedule 20.01.2011    source источник


Ответы (1)


BufferedOutputStream имеют кеш в Java, а FileChannel его нет.

Однако у FileChannel есть кеш уровня ОС. В котором .force() совпадает с fsync / fdatasync.

В 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 }

Прочтите этот блог, если хотите узнать больше о том, как ОС работает на этом уровне.

person J-16 SDiZ    schedule 20.01.2011
comment
Так что нет причин делать дополнительную буферизацию на уровне java для FileChannel? т. е. что, если я буду использовать только ByteBuffer 64K-256K и просто заполнять его необходимой информацией, пока он не переполнится, а затем бросить его в FileChannel#write? Является ли это решение лучшим с использованием FileChannel? - person Alexander Shukaev; 20.01.2011
comment
@Haroogan, (1) каждая запись в FileChannel является системным вызовом - это связано с некоторыми накладными расходами на уровне ОС; (2) буфер на уровне java более предсказуем и настраивается; (3) запись блока размером 4 КБ (выровненного) часто дает наилучшую производительность; (4) сделать свой собственный тест - person J-16 SDiZ; 20.01.2011
comment
comment
FileChannel не имеет кэша на уровне ОС. Это делает операционная система, и она делает это для каждого открытого файла. Или не. Никакого отношения конкретно к FileChannel. - person user207421; 24.05.2017