DataInputStream.read возвращает меньше чем len
Я использую DataInputStream для чтения некоторых байтов из сокета. У меня есть ожидаемое количество байтов для чтения из потока (после декодирования заголовка я знаю, сколько байтов содержится в сообщении). Это работает в 99% случаев, но иногда я получаю количество прочитанных байтов меньше, чем len.
int numRead = dis.read(buffer, 0, len);
Что может стать причиной того, что numRead будет меньше, чем len? Это не -1. Я ожидал бы, что поведение чтения будет блокироваться, пока поток не будет закрыт или пока не будет достигнут EOF, но если это сокет, лежащий в основе потоков, этого не должно произойти, если сокет не закроется, верно?
Есть ли способ чтения байтов из сокета, который всегда гарантирует, что вы читаете len байтов?
Спасибо
4 ответа
РЕДАКТИРОВАТЬ: Для общего потока, вы просто продолжаете читать, пока вы не прочитаете все, что вы хотите, в основном. Для реализации DataInput
(такие как DataInputStream
) вы должны использовать readFully
, как предположил Питер Лори. Считайте, что остальная часть этого ответа важна для общего случая, когда у вас просто есть InputStream
,
Это вполне разумно для InputStream
любого типа, чтобы дать вам меньше данных, чем вы просили, даже если больше в пути. Вы должны всегда кодировать эту возможность - с возможным исключением ByteArrayInputStream
, (Конечно, это может вернуть меньше данных, чем было запрошено, если осталось меньше данных, чем вы просили.)
Вот такая петля, о которой я говорю:
byte[] data = new byte[messageSize];
int totalRead = 0;
while (totalRead < messageSize) {
int bytesRead = stream.read(data, totalRead, messageSize - totalRead);
if (bytesRead < 0) {
// Change behaviour if this isn't an error condition
throw new IOException("Data stream ended prematurely");
}
totalRead += bytesRead;
}
Вы можете использовать DataInputStream таким образом.
byte[] bytes = new byte[len];
dis.readFully(bytes);
Это либо вернет все прочитанные данные, либо выдаст IOException.
Чтение возвращает каждый раз с битами, которые были доступны в то время, и -1, когда вы закончите, вы обычно должны делать
while (true) {
int numRead = dis.read(buffer, 0, len);
if (numRead == -1) break;
total.append(buffer, numRead);
}
Есть ли способ чтения байтов из сокета, который всегда гарантирует, что вы прочитаете len байтов?
Вы можете использовать Apache Commons IOUtils, у них есть метод, который делает именно то, что вам нужно:
byte[] buf = new byte[BUFFER_SIZE];
int length;
do {
length = IOUtils.read(inputStream, buf);
if (length > 0) {
//do something with buf
}
} while (length == BUFFER_SIZE);
Я ожидал бы, что поведение чтения будет блокироваться, пока поток не будет закрыт или не будет достигнут EOF.
Тогда вам нужно проверить Javadocs. Контракт read() заключается в том, что он будет читать по крайней мере один байт, блокируя при необходимости, пока это не будет сделано, или пока не произойдет EOS или исключение. В спецификации ничего не сказано о том, что он будет читать всю запрашиваемую вами длину. Вот почему он возвращает длину.