2

I've something that I don't understand, please help.

System.out.println("\n" + Arrays.toString(buffer) + "\n");
System.out.println("buffer.length = " + buffer.length + "\nnew ByteArrayInputStream(buffer).available() is: " + new ByteArrayInputStream(buffer).available());
ObjectInput input = new ObjectInputStream(new ByteArrayInputStream(buffer));
System.out.println("input.available(): " + input.available());

Its output is below:

[-84, -19, 0, 5]

buffer.length = 4
new ByteArrayInputStream(buffer).available() is: 4
input.available(): 0

I'm so confused why a byte array of 4 valid bytes, after putting into ObjectInputStream, it becomes zero.

Things I've tried:

  1. Initially, I was doubting my byte array was empty, but as you see, I printed out, its length is 4.
  2. Then I thought my byte might be invalid, so I printed out each byte, as you can see, those four bytes are all valid.

So, I'm lost why this is happening.

Please help, thanks a lot!

Fisher Coder
  • 3,278
  • 12
  • 49
  • 84
  • What is the input data? At 4 bytes, it seems unlikely to be an object. As the docs say, `An ObjectInputStream deserializes primitive data and objects previously written using an ObjectOutputStream.` – Christopher Schneider Feb 04 '17 at 01:22
  • How can I show the input? I thought Arrays.toString(buffer) was the best I could show. – Fisher Coder Feb 04 '17 at 01:25
  • So here's the issue in my previous comment: `data and objects previously written using an ObjectOutputStream`. You don't do this. You are reading raw bytes that have never passed through an `ObjectInputStream`. – Christopher Schneider Feb 04 '17 at 01:30

2 Answers2

6

As the other answer mentioned, available only means the number of bytes you can read before blocking occurs.

It is my guess, however, that you didn't follow the rules of the ObjectInputStream, which specify An ObjectInputStream deserializes primitive data and objects previously written using an ObjectOutputStream.

In other words, in order to actually read the data with an ObjectInputStream, you first must have written the data using an ObjectOutputStream of some kind. Here's an example showing this with the data you provided:

byte[] buffer = new byte[]{-84,-19,0,5};
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream= new ObjectOutputStream(out);
objectOutputStream.write(buffer);
objectOutputStream.flush();

ObjectInput input = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray()));
System.out.println("input.available(): " + input.available());
System.out.println("input.readByte(): " + input.readByte());

(I'll add that I very rarely work with IO in Java, so the above may not be best practice or have superfluous code.)

Christopher Schneider
  • 3,745
  • 2
  • 24
  • 38
1

Here is the javadoc of available method and this is what it says:

Returns the number of bytes that can be read without blocking.

So, it does not return the total number of bytes present in your array/read, it returns the number of bytes it can read before getting blocked. So, it returning 0 is a valid scenario.

Now, let's have a look at javadoc of ObjectInputStream, here is the brief explanation:

Non-object reads which exceed the end of the allotted data will reflect the end of data in the same way that they would indicate the end of the stream: bytewise reads will return -1 as the byte read or number of bytes read, and primitive reads will throw EOFExceptions. If there is no corresponding writeObject method, then the end of default serialized data marks the end of the allotted data.

What you are trying to do in your code is to read the primitive data (or reading without WriteObject method), as it is not valid data (for ObjectInputStream) read will always return -1. And I was able to reproduce EOFExceptionjust by calling readObject method.

I then tried writing/reading a new object and tested available method call, have a look at the below snippet:

byte[] buffer = new byte[]{-84, -19, 0, 5};
System.out.println("\n" + Arrays.toString(buffer) + "\n");
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(buffer);
System.out.println("buffer.length = " + buffer.length + "\nnew ByteArrayInputStream(buffer).available() is: " + new ByteArrayInputStream(buffer).available());
ObjectInputStream input = new ObjectInputStream(byteArrayInputStream);
System.out.println("input.available(): " + input.available());
//      System.out.println(input.readObject()); //Uncomment to see EOFException

Date date = new Date();
System.out.println(date);
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteArrayOut);
out.writeObject(date);
byte[] bytes = byteArrayOut.toByteArray();

input = new ObjectInputStream(new ByteArrayInputStream(bytes));
System.out.println(input.available());
System.out.println(input.readObject());

The code reads the already written object and prints the value. Please note that even though it reads the object correctly and prints the same object, available method still returns 0. So, I would recomment not to rely too much on available because of it's misleading name :)

Darshan Mehta
  • 30,102
  • 11
  • 68
  • 102