Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java InputStream reading problem

I have a Java class, where I'm reading data in via an InputStream

    byte[] b = null;
    try {
        b = new byte[in.available()];
        in.read(b);
    } catch (IOException e) {
        e.printStackTrace();
    }

It works perfectly when I run my app from the IDE (Eclipse).

But when I export my project and it's packed in a JAR, the read command doesn't read all the data. How could I fix it?

This problem mostly occurs when the InputStream is a File (~10kb).

Thanks!

like image 815
Michael Avatar asked May 28 '11 07:05

Michael


People also ask

Is InputStream read blocking?

According to the java api, the InputStream. read() is described as: If no byte is available because the end of the stream has been reached, the value -1 is returned. This method blocks until input data is available, the end of the stream is detected, or an exception is thrown.

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. In addition, you could not return value above 127 or below -128 because Java only handles signed bytes.

What happens if InputStream not closed?

InputStream or its subclasses? Now with java. io. OutputStream , say FileOutputStream , after writing to a file, if we don't close() the output stream, the data that we intended to write in the file remains in the buffer and is not written to the file.

What is InputStream read in java?

An InputStreamReader is a bridge from byte streams to character streams: It reads bytes and decodes them into characters using a specified charset. The charset that it uses may be specified by name or may be given explicitly, or the platform's default charset may be accepted.


1 Answers

Usually I prefer using a fixed size buffer when reading from input stream. As evilone pointed out, using available() as buffer size might not be a good idea because, say, if you are reading a remote resource, then you might not know the available bytes in advance. You can read the javadoc of InputStream to get more insight.

Here is the code snippet I usually use for reading input stream:

byte[] buffer = new byte[BUFFER_SIZE];

int bytesRead = 0;
while ((bytesRead = in.read(buffer)) >= 0){
  for (int i = 0; i < bytesRead; i++){
     //Do whatever you need with the bytes here
  }
}

The version of read() I'm using here will fill the given buffer as much as possible and return number of bytes actually read. This means there is chance that your buffer may contain trailing garbage data, so it is very important to use bytes only up to bytesRead.

Note the line (bytesRead = in.read(buffer)) >= 0, there is nothing in the InputStream spec saying that read() cannot read 0 bytes. You may need to handle the case when read() reads 0 bytes as special case depending on your case. For local file I never experienced such case; however, when reading remote resources, I actually seen read() reads 0 bytes constantly resulting the above code into an infinite loop. I solved the infinite loop problem by counting the number of times I read 0 bytes, when the counter exceed a threshold I will throw exception. You may not encounter this problem, but just keep this in mind :)

I probably will stay away from creating new byte array for each read for performance reasons.

like image 138
Alvin Avatar answered Oct 23 '22 03:10

Alvin