Search code examples
javainputstreamfileinputstream

InputStream reader


I'm currently trying to read in a image file from the server but either getting a incomplete data or

Exception in thread "main" 
         java.lang.NegativeArraySizeException. 

Has this something to do with the buffer size? I have tried to use static size instead of contentlength. Please kindly advise.

  URL myURL = new URL(url);
  HttpURLConnection connection = (HttpURLConnection)myURL.openConnection();
  connection.setRequestMethod("GET");
  status = connection.getResponseCode();

  if (status == 200)
  {
    int size = connection.getContentLength() + 1024;
    byte[] bytes = new byte[size];
    InputStream input = new ByteArrayInputStream(bytes);
    FileOutputStream out = new FileOutputStream(file);
    input = connection.getInputStream();

    int data = input.read(bytes);
    while(data != -1){
       out.write(bytes);
       data = input.read(bytes);
    }
    out.close();
    input.close();

Solution

  • Let's examine the code:

    int size = connection.getContentLength() + 1024;
    byte[] bytes = new byte[size];
    

    why do you add 1024 bytes to the size? What's the point? The buffer size should be something large enough to avoid too many reads, but small enough to avoid consuming too much memory. Set it at 4096, for example.

    InputStream input = new ByteArrayInputStream(bytes);
    FileOutputStream out = new FileOutputStream(file);
    input = connection.getInputStream();
    

    Why do you create a ByteArrayInputStream, and then forget about it completely? You don't need a ByteArrayInputStream, since you don't read from a byte array, but from the connection's input stream.

    int data = input.read(bytes);
    

    This reads bytes from the input. The max number of bytes read is the length of the byte array. The actual number of bytes read is returned and stored in data.

    while (data != -1) {
        out.write(bytes);
        data = input.read(bytes);
    }
    

    So you have read data bytes, but you don't write only the first data bytes of the array. You write the whole array of bytes. That is wrong. Suppose your array if of size 4096 and data is 400, instead of writing the 400 bytes that have been read, you write the 400 bytes + the remaining 3696 bytes of the array, which could be 0, or could have values coming from a previous read. It should be

    out.write(bytes, 0, data);
    

    Finally:

    out.close();
    input.close();
    

    If any exception occurs before, those two streams will never be closed. Do that a few times, and your whold OS won't have file descriptos available anymore. Use the try-with-resources statement to be sure your streams are closed, no matter what happens.