Java DataInputStream.read返回的长度小于len
我正在使用DataInputStream从套接字读取一些字节。我有一个从流中读取的预期字节数(在解码一个报头后,我知道消息中有多少字节),它99%的时间工作,但偶尔我会让读取的字节数小于len 是什么导致numRead小于len?不是-1。我希望在流关闭或达到EOF之前,读取行为都会被阻塞,但是如果它是流下面的套接字,除非套接字关闭,否则不应该发生这种情况,对吗 是否有一种从套接字读取字节的方法可以确保您始终读取len字节Java DataInputStream.read返回的长度小于len,java,sockets,inputstream,datainputstream,Java,Sockets,Inputstream,Datainputstream,我正在使用DataInputStream从套接字读取一些字节。我有一个从流中读取的预期字节数(在解码一个报头后,我知道消息中有多少字节),它99%的时间工作,但偶尔我会让读取的字节数小于len 是什么导致numRead小于len?不是-1。我希望在流关闭或达到EOF之前,读取行为都会被阻塞,但是如果它是流下面的套接字,除非套接字关闭,否则不应该发生这种情况,对吗 是否有一种从套接字读取字节的方法可以确保您始终读取len字节 谢谢编辑:对于一般的流,您只需继续阅读,直到您基本上已经阅读了所有您想要
谢谢编辑:对于一般的流,您只需继续阅读,直到您基本上已经阅读了所有您想要的内容。对于
DataInput
(例如DataInputStream
)的实现,您应该像Peter Lawrey建议的那样,使用。考虑剩下的这个答案和一般情况下的情况有关,你只有一个<代码>输入流< /代码>。
任何类型的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;
}
byte[]data=新字节[messageSize];
int totalRead=0;
while(totalRead
read每次都返回当时可用的位,完成时返回-1,这通常是您应该执行的操作
while (true) {
int numRead = dis.read(buffer, 0, len);
if (numRead == -1) break;
total.append(buffer, numRead);
}
您可以这样使用DataInputStream
byte[] bytes = new byte[len];
dis.readFully(bytes);
这将返回所有读取的数据或引发IOException
我希望read的行为
阻塞,直到流关闭或关闭
达到EOF
然后您需要检查Javadocs。read()的约定是,它将读取至少一个字节,必要时将阻塞,直到读取完毕,或者直到EOS或异常发生。规范中没有说明它将读取您要求的整个长度。这就是它返回长度的原因
是否有一种从套接字读取字节的方法可以确保您始终读取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);
ByteArrayInputStream
如果到达其末尾,读取的数据仍将少于请求的数据。@Stephen:没错,但如果您完全知道那里有更多的数据,那么我会非常惊讶地看到它返回的数据更少。我会编辑来澄清的。很好的解释了发生了什么。然而,我认为Peter Lawrey关于Readfull的建议比使用while循环来读取全部数据更干净。@Dunes:在DataInputStream的情况下,你完全正确:)我没有注意到这一点。对于非DataInput,使用循环版本非常有用。将编辑。是的,len在这里可以是常数,例如1024
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);