Вопрос с собеседования · Java

Почему чтение файла по одному байту через FileInputStream радикально медленнее, чем через BufferedInputStream?

MiddleВвод-вывод и NIO
Ещё спрашивают так:
  • Зачем нужна буферизация при вводе-выводе?
  • Зачем нужна буферизация при вводе-выводе и что происходит, если читать файл без неё?
Коротко

Дорог не байт, а системный вызов с переходом в ядро. Чтение по байту из FileInputStream — по вызову на байт; BufferedInputStream читает блок (8 КБ) за один вызов и отдаёт байты из памяти — разница на порядки.

  • При записи то же — плюс flush() перед закрытием или ожиданием ответа
  • Читать массивами (read(byte[])) — тот же эффект без обёртки
  • Files.readAllBytes, transferTo — уже эффективны

А ещё Забытый flush — данные «потерялись» в буфере

Подробно

Системный вызов требует переключения контекста между пользовательским режимом и ядром, и его стоимость на порядки превышает копирование байта из памяти. Буферизующая обёртка читает блок разом и обслуживает последующие обращения из него. Ровно тот же принцип действует при записи, с важным дополнением: данные остаются в буфере, пока он не заполнится, поэтому забытые flush или close приводят к потере хвоста файла — try-with-resources решает и это. Стоит помнить, что буферизация не бесплатна и не всегда нужна: если вы и так читаете крупными массивами, дополнительный слой лишь копирует данные ещё раз.

Что хотят услышать

  • Стоимость системного вызова.
  • Как буфер её снимает.
  • flush при записи.

Частые ошибки

  • Забыть закрыть или сбросить буферизованный поток записи и потерять данные.
  • Оборачивать в буфер поток, который и так читается большими блоками.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✗FileInputStream проверяет права доступа к файлу при каждом обращении
  • ✓Каждый байт — системный вызов, а буфер читает блоками
  • ✗BufferedInputStream использует несколько потоков для чтения
  • ✗Буферизация сжимает данные, поэтому их меньше

Что спросят дальше

  • Что произойдёт, если не вызвать close у BufferedWriter?
  • Где в этой конструкции проявляется паттерн Decorator?
  • Почему у BufferedReader есть readLine, а у InputStream нет?
  • Когда буферизация не нужна или даже вредна?

Разбор темы

Связанные вопросы

Партнёр платформы

Разбор собеседования с sotto

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования