Java = Буфер загрузки не заполнен полностью? Как работает флюсинг / буферизация? - PullRequest
1 голос
/ 02 августа 2011

Я хочу следить за ходом загрузки данных.Я хочу войти после того, как определенное количество данных было передано.Мой код:

int contentLength = 0;
final int bufferSize = 1024*8;
byte[] buffer = new byte[bufferSize];
int length = 0;

while ( (length = bufferedInputStream.read(buffer) ) !=-1 ) {
    contentLength = contentLength+length;

    if ( (contentLength % (bufferSize*1024*4)) ==0 ) {
                logger.debug(contentLength);
    }   
}

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

Действительно ли это часто, что буфер не "заполнен"?Как это может случиться?Какова внутренняя логика, по которой "буфер" "очищается"?Ожидает ли Java определенное время для получения пакетов, а затем сбрасывается (если буфер не заполнен)?Любая информация о том, как это внутренне работает, была бы полезна для понимания.

(мне не нужно решение, я его реализовал другим, просто интересно, распространено ли это, что буфер никогда полностью не читается?Любопытно понять почему.)

Спасибо большое!Jens

Ответы [ 4 ]

1 голос
/ 02 августа 2011

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

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

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

0 голосов
/ 02 августа 2011

Это эффективно зависит от фактического InputStream, который вы использовали, и сводится к тому, «как ОС обрабатывает read() вызовы».

В большинстве современных операционных систем базовый вызов read делает то же самое: он пытается прочитать столько данных, сколько было запрошено, но может остановиться раньше.

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

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

Итак: да, это легко может произойти.

0 голосов
/ 02 августа 2011

Когда вы можете использовать API read(byte[], ...), поток попытается заполнить выделенное пространство в буфере.Но это не всегда заполняет это.Конечно, если содержимое в потоке заканчивается, он не может заполнить все пространство.Но есть и другие причины.Например, потоковая реализация может использовать некоторый фоновый поток для извлечения данных.Если вызов read передается в операционную систему, он может читать один блок данных за раз.Если поток буферизован, а в буфере все еще есть содержимое, он может просто вернуть то, что осталось в буфере.

0 голосов
/ 02 августа 2011

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

...