-1

My understanding of BufferedInputStream.read(byte[]) is that the read operation starts from pos, and reads until either the byte array is full or end of stream occurs.

I am calling the readInt method below on a BufferedInputStream.

public class XDRInputStream {

private InputStream stream;

private byte[] buffer4 = new byte[4]; // fixed size buffers
private byte[] buffer8 = new byte[8];

public XDRInputStream(InputStream stream) {
    this.stream = stream;
}

public InputStream getInternalStream() {
    return stream;
}

public int readInt() throws IOException {
    if (stream.read(buffer4) != -1) {
        return ((buffer4[0] & 0xFF) << 24)
             | ((buffer4[1] & 0xFF) << 16)
             | ((buffer4[2] & 0xFF) << 8)
             | ((buffer4[3] & 0xFF));
    } else {
        throw new EOFException("End of stream");
    }
}

When I track execution in the Eclipse debugger, the stream.read(buffer4) call - regardless of the starting pos value - usually results in the value of pos being set to 4, and the 4 bytes read are the first four bytes from the input stream. Does the read(byte[]) call quietly reset the stream in certain circumstances, and if so, when? This seems to be intended behaviour (this is not my code), and when it operates this way, the program functions fine.

The problem I am experiencing is that sometimes, only on Windows and only when the input stream contains specific contents (an error message resulting from a dropped socket upstream, in this case), this resetting of pos does NOT occur when it seems to be intended to, which results in the method reading from an incorrect position in the stream and returning an incorrect value.

We use the same code on Solaris, and while I have not done a debugger step-through on this platform, under Solaris the program works fine and the bug I'm attempting to fix does not occur. Could there be some platform-specific issue with streams I'm not aware of?

Thanks.

gjr
  • 1
  • 1

2 Answers2

2

As a rule of thumb, you can't rely on entire array being read from the stream in one shot. If you look at docs you will see that return of read(byte[]) is a number of bytes read which may be entire array length or less. Or even 0 if no data is yet there. And it's very typical (and probably OS dependent) to read less than entire array.

So you have to make sure that you actually read 4 bytes.

Alex Gitelman
  • 24,429
  • 7
  • 52
  • 49
  • You're right of course, and that check is an improvement I should make to the code, but I don't think this is the cause of my immediate problem. Just looking at the stream buffer contents I can tell that the data is there, and 4 bytes are indeed read from the buffer as expected - just from an unexpected starting point. – gjr Jul 10 '12 at 06:06
  • worked out what the problem was - if pos is equal to the last byte in the buffer, read(bytes[]) will assume that the buffer has been completely read already, and call fill() to overwrite the contents with new stuff. Fix for this will have to be implemented in my upstream code. – gjr Jul 10 '12 at 08:06
  • @glr The only way that `pos` can be at the end of the buffer is if it *has* been fully read already, or skipped. No 'assume' about it. – user207421 Oct 20 '14 at 21:20
1

My understanding of BufferedInputStream.read(byte[]) is that the read operation starts from pos, and reads until either the byte array is full or end of stream occurs.

Your understanding is incorrect.

Your understanding is flatly contradicted by the Javadoc, which says that it blocks if necessary until at least one byte is available, reads whatever is available, and returns the count of the number of bytes read, or -1 if EOS was read instead.

user207421
  • 305,947
  • 44
  • 307
  • 483