Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DataInputStream.read returning less than len

I am using DataInputStream to read some bytes from a socket. I have a expected number of bytes to read from the stream (after decoding a header, I know how many bytes are in the message) It works 99% of the time but occasionally I will have the number of bytes read be less than len.

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

What could cause numRead to be less than len? It's not -1. I would expect the behavior of read to block until the stream is closed or EOF is reached, but if it's a socket underlying the streams this shouldn't happen unless the socket closes, right?

Is there a way of reading bytes from a socket that will always ensure that you read len bytes?

Thanks

like image 978
barab157 Avatar asked Jan 12 '11 20:01

barab157


People also ask

What is meant by DataInputStream in Java?

A data input stream lets an application read primitive Java data types from an underlying input stream in a machine-independent way. An application uses a data output stream to write data that can later be read by a data input stream. DataInputStream is not necessarily safe for multithreaded access.

Why use DataInputStream in Java?

A data input stream enables an application to read primitive Java data types from an underlying input stream in a machine-independent way(instead of raw bytes). That is why it is called DataInputStream – because it reads data (numbers) instead of just bytes.

What is the difference between DataInputStream and BufferedInputStream in Java?

DataInputStream is a kind of InputStream to read data directly as primitive data types. BufferedInputStream is a kind of inputStream that reads data from a stream and uses a buffer to optimize speed access to data. data is basicaly read ahead of time and this reduces disk or network access.

Why does InputStream read return an int?

It returns an int because when the stream can no longer be read, it returns -1. If it returned a byte, then -1 could not be returned to indicate a lack of input because -1 is a valid byte.


2 Answers

EDIT: For a general stream, you just keep reading until you've read everything you want to, basically. For an implementation of DataInput (such as DataInputStream) you should use readFully, as suggested by Peter Lawrey. Consider the rest of this answer to be relevant for the general case where you just have an InputStream.

It's entirely reasonable for an InputStream of any type to give you less data than you asked for, even if more is on its way. You should always code for this possibility - with the possible exception of ByteArrayInputStream. (That can still return less data than was requested, of course, if there's less data left than you asked for.)

Here's the sort of loop I'm talking about:

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;
}
like image 69
Jon Skeet Avatar answered Sep 22 '22 07:09

Jon Skeet


You can use DataInputStream this way.

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

This will either return with all the data read or throw an IOException.

like image 30
Peter Lawrey Avatar answered Sep 24 '22 07:09

Peter Lawrey