Can I read an entire file with a single read in java on android?

问题描述:

On android when reading from an input stream that represents a file on the internet if I request a read of the entire length of the file is there any reason why my byte array should only be partially filled after the call?

网友答案:

The read(byte[]) method on Java streams may read less bytes than requested.

By file on the internet I assume you mean the contents of an HTTP URL.

Some HTTP responses will not give a Content-Length in advance which also doesn't makes it possible to pre-allocate a byte array of the right size as you seem to be doing.

You may be interested to know that the Apache http client library available on Android already provides an helper method EntityUtils.toByteArray() that fully fetches the content of an URL and returns it as a properly sized byte array.

Note that reading the whole response in memory is not always the best solution. It may be preferable to report the download progress to the user or parse a large document incrementally. In fact a response may not even fit in RAM (e.g a large video stream).

网友答案:

The normal read command reads some number of bytes up to the requested length. It is up to the programmer to include a check of the return value (which tells you how many bytes were read). There is also the readFully method which forces it to read the entire length requested, but that has the potential to block for a very long time, preventing you from breaking out in the middle of reading a large stream.

网友答案:

is there any reason why my byte array should only be partially filled after the call?

Yes. So that your android application doesn't have to wait for the entire stream to download before returning from the read call.

In your particular use case, this is (apparently) a nuisance. In other use cases, it is a critical requirement that read behaves this way:

The application may need to start processing and delivering results to the user while remote server is still sending the data.

The remote server may actually be waiting for some kind of application level response from client before sending more data. (This won't apply if you are using HTTP or FTP. But the stream you are reading from is probably wrapping a transport-layer Socket stream, and at that level there is no knowledge about any presentation-layer protocol details.)

The solution is to:

Use a loop and keep reading until read returns zero.

If you are using Apache HttpClient, there are ways to get the entire content of a response.

The Apache Commons includes an IOUtils class that has helper methods for reading an entire stream or reader.

BTW, this behaviour is clearly specified in the javadocs for the read(byte[], ...) methods.