FileInputStream читает побайтово или блокирует? - PullRequest
0 голосов
/ 22 января 2020

Причина, по которой bufferedinputstream (BIS) работает быстрее, чем FileInputStream (FIS), предоставленный на Почему BufferedInputStream для чтения байта файла побайтнее, чем FileInputStream? в том, что

При использовании BufferedInputStream метод делегирует перегруженному методу read (), который читает 8192 байтов и буферизует их до тех пор, пока они не потребуются, пока FIS читает один байт

По моему пониманию, диск является «блочное устройство». Диск всегда будет читать / записывать целые блоки, даже если запрос на чтение для некоторого меньшего количества данных. Не так ли? Так как даже FIS и BIS будут считывать полный блок, а не один байт (как указано для FIS). Правильно ? Так как же BIS быстрее, чем FIS?

1 Ответ

0 голосов
/ 22 января 2020

API java InputStream такой, какой он есть. В частности, у него есть такой метод:

int read() throws IOException

, который читает один байт (он возвращает int, чтобы он мог вернуть -1, чтобы указать EOF).

Итак, если вы попытаетесь чтобы прочитать один байт из файла, он попытается это сделать. В случае блочного устройства, такого как жесткий диск, он, скорее всего, прочитает весь блок, а затем зафиксирует все, кроме одного байта, поэтому, если вы вызываете этот метод read() 8192 раза, он читает один и тот же блок снова и снова. более 8192 раз, каждый раз отбрасывая 8191 байт и давая вам именно тот, который вам нужен. Таким образом, чтение 67 миллионов байт за весь процесс. Уч. Не очень эффективно.

Учитывая, что ядро, процессор, диск и т. Д. c все читаются с размером блока 8192, нулевая разница в производительности между BufferedInputStream(new FileInputStream) и new FileInputStream, ЕСЛИ вы используете что-то вроде:

byte[] buffer = new byte[8192];
in.read(buffer);

Теперь даже обычная Джейн без буферизации new FileInputStream просто заканчивает чтение этого блока с диска всего один раз.

BufferedInputStream делает это «под капотом», даже если вы используете однобайтовую форму read(), и затем будете подавать вам данные из этого байтового массива для следующих 8191 вызовов на read(). Это все, что делает BufferedInputStream.

Если вы используете вариант read() (по одному байту за раз) (или вариант чтения байтового массива, но с очень маленькими байтовыми массивами), тогда BufferedInputStream имеет смысл. В противном случае это ничего не делает, и нет необходимости помещать это туда.

Примечание: насколько я знаю, java не догадывается о том, каков размер дискового буфера, и просто использует некоторый разумный размер буфера , Эффект тот же: если вы используете один байт за раз, оборачивание вашего файлового потока в поток с буферизацией повышает производительность более чем в 1000 раз, если вы используете вариант байтового массива, никакой разницы нет.

...