DataInputStream.read возвращает меньше чем len - PullRequest
5 голосов
/ 12 января 2011

Я использую DataInputStream для чтения некоторых байтов из сокета.У меня есть ожидаемое число байтов для чтения из потока (после декодирования заголовка я знаю, сколько байтов содержится в сообщении). Это работает в 99% случаев, но иногда я получаю число прочитанных байтов меньше, чем * 1001.* LEN .

int numRead = dis.read(buffer, 0, len);

Что может стать причиной того, что numRead будет меньше len?Это не -1.Я ожидал бы, что поведение чтения будет блокироваться до тех пор, пока поток не будет закрыт или пока не будет достигнут EOF, но если это сокет, лежащий в основе потоков, этого не произойдет, если сокет не закроется, верно?чтение байтов из сокета, который всегда гарантирует, что вы читаете len байтов?

Спасибо

Ответы [ 4 ]

11 голосов
/ 12 января 2011

РЕДАКТИРОВАТЬ: Для общего потока, вы просто продолжаете читать, пока вы не прочитаете все, что вы хотите, в основном. Для реализации 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;
}
8 голосов
/ 13 января 2011

Вы можете использовать DataInputStream таким способом.

byte[] bytes = new byte[len];
dis.readFully(bytes);

Это вернет либо все прочитанные данные, либо выдаст IOException.

0 голосов
/ 13 января 2011

Я ожидаю, что поведение чтения будет блокироваться до тех пор, пока поток не закроется или не будет достигнут EOF.

Затем необходимо проверить Javadocs.Контракт read () заключается в том, что он будет читать по крайней мере один байт, блокируя при необходимости, пока это не будет сделано, или пока не произойдет EOS или исключение.В спецификации ничего не говорится о том, что он будет читать всю запрашиваемую вами длину.Вот почему он возвращает длину.

0 голосов
/ 13 января 2011

read возвращается каждый раз с битами, которые были доступны в то время, и -1, когда вы закончите, вы обычно должны делать

while (true) {
  int numRead = dis.read(buffer, 0, len);
  if (numRead == -1) break;
  total.append(buffer, numRead);
}
...