Что не так с FileInputStream.read (byte [])? - PullRequest
7 голосов
/ 25 мая 2011

В ответ на мой ответ на вопрос о чтении файла , комментатор заявил, что FileInputStream.read(byte[]) "не гарантирует заполнение буфера".

File file = /* ... */  
long len = file.length();
byte[] buffer = new byte[(int)len];
FileInputStream in = new FileInputStream(file);
in.read(buffer);

(Кодпредполагается, что длина файла не превышает 2 ГБ)

Помимо IOException, что может заставить метод read не извлекать все содержимое файла?

РЕДАКТИРОВАТЬ:

Идея кода (и цель ОП вопроса, на который я ответил) состоит в том, чтобы одним махом прочитать весь файл в кусок памяти, поэтому buffer_size = file_size .

Ответы [ 6 ]

6 голосов
/ 25 мая 2011

что может вызвать метод чтения не получить все содержимое файла?

Если, например, файл фрагментирован в файловой системе, и низкоуровневая реализация знает, что ему придется ждать, пока HD выполнит поиск следующего фрагмента (что занимает много времени относительно ЦП). операции), имеет смысл возвращать вызов read() с незаполненной частью буфера, чтобы дать приложению возможность уже что-то делать с полученными данными.

Теперь я не знаю, работает ли какая-либо реализация на самом деле так, но дело в том, что вы не должны полагаться на заполненный буфер, потому что это не гарантируется контрактом API.

5 голосов
/ 25 мая 2011

Что может привести к тому, что метод чтения не получит все содержимое файла, кроме IOException?

В моем собственном APIреализации, и в моей домашней файловой системе я просто выбираю заполнить половину буфера ...... просто шучу.

Моя точка зрения такова, что даже если бы я не шутил, технически говоря, это не будет 'быть ошибкойЭто вопрос метода контракта.Это контракт (документация) в данном случае:

Считывает до b.length байтов данных из этого входного потока в массив байтов.

т. Е. Он не дает никаких гарантий для заполнения буфера.

В зависимости от реализации API и, возможно, от файловой системы метод read может не заполнять буфер.Это в основном вопрос о том, что говорится в контракте метода.


Итог: Это вероятно работает, но не гарантируется 1034 * для работы.

3 голосов
/ 25 мая 2011

Ну, во-первых, вы сделали себе ложную дихотомию.Одно совершенно нормальное обстоятельство заключается в том, что буфер не будет заполнен, потому что в файле осталось не так много байтов.Это не IOException, но это не означает, что содержимое всего файла не было прочитано.

В спецификации сказано, что метод либо возвратит -1, указывая конец потока, либо заблокирует дохотя бы один байт читается.Реализаторы InputStream могут оптимизировать по своему усмотрению (например, поток TCP может возвращать данные, как только поступит пакет, независимо от выбора размера буфера вызывающей стороной).FileInputStream может заполнить буфер данными из одного блока.Как вызывающий пользователь, вы понятия не имеете, за исключением того, что пока метод не вернет -1, вам нужно продолжать читать.

Редактировать

На практике, на вашем примере, единственным обстоятельством, которое я хотел быПосмотрите, где буфер не будет заполнен (со стандартной реализацией), если размер файла изменился после того, как вы выделили буфер, но до того, как начали его читать.Поскольку вы не заблокировали файл, это возможно.

2 голосов
/ 25 мая 2011

Люди говорили о том, что чтение на FileInputStream как гипотетически не заполняет буфер.На самом деле это реальность при некоторых обстоятельствах:

  • Если вы откроете FileInputStream для "/ dev / tty" или именованного канала, то read вернет вам только те данные, которые доступны в данный момент.Другие файлы устройств могут вести себя так же.(Эти файлы, вероятно, вернут 0L в качестве размера файла.)

  • A FUSE файловая система может быть реализована так, чтобы не полностью заполнять буфер чтения, еслифайловая система была смонтирована с опцией direct_io, или файл открывается с соответствующим флагом.

Вышеуказанное относится к Linux, но вполне могут быть аналогичные случаи для других операционных систем.системы и / или реализации Java.Суть в том, что javadocs допускает такое поведение, и вы можете столкнуться с проблемами, если ваше приложение считает, что этого не произойдет.

Существуют сторонние библиотеки, которые реализуют «чтение полностью»поведение;например, Apache commons предоставляет FileUtils.readFileToByteArray или IOUtils.toByteArray и аналогичные методы.Если вы хотите / нуждаетесь в таком поведении, вам следует использовать одну из этих библиотек или реализовать ее самостоятельно.

1 голос
/ 25 мая 2011

Не гарантируется Заполнение буфера.

Размер файла может быть меньше размера буфера, или остаток файла может быть меньше размера буфера.

0 голосов
/ 26 мая 2011

Ваш вопрос противоречив. Нет никаких гарантий, что он будет читать весь буфер, даже если нет никаких мыслимых обстоятельств, при которых он не будет. Там нет никакой гарантии, поэтому вы не можете принять это.

...