3

I have code block to read mentioned number of bytes from an InputStream and return a byte[] using ByteArrayOutputStream. When I'm writing that byte[] array to a file, resultant file on the filesystem seems broken. Can anyone help me find out problem in the below code block.

public byte[] readWrite(long bytes, InputStream in) throws IOException {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    int maxReadBufferSize = 8 * 1024; //8KB
    long numReads = bytes/maxReadBufferSize;
    long numRemainingRead = bytes % maxReadBufferSize;
    for(int i=0; i<numReads; i++) {
        byte bufr[] = new byte[maxReadBufferSize];
        int val = in.read(bufr, 0, bufr.length);
        if(val != -1) {
            bos.write(bufr);
        }
    }
    if(numRemainingRead > 0) {
        byte bufr[] = new byte[(int)numRemainingRead];
        int val = in.read(bufr, 0, bufr.length);
        if(val != -1) {
            bos.write(bufr);
        }
    }
    return bos.toByteArray();
}
  • 1
    `bos.write(bufr)` should be `bos.write(bufr, 0, val)`, and similarly for the other write. You're not taking account of the actual length read, so you're writing garbage to the file. You should also loop with `while ((val = in.read(bufr)) > 0)`, not with a `for` loop, as you don't know in advance how many reads will be required. This also gets rid of the second block, as you will exhaust the input with the first block. And allocate the buffer before the loop, to create much less garbage. – user207421 Nov 15 '19 at 06:22
  • I'm getting numBytes to be read as a param `long bytes` and I'm calculating no.of iterations by `long numReads = bytes/maxReadBufferSize;` and remaining bytes to read using `long numRemainingRead = bytes % maxReadBufferSize;` then why it fails that's what i don't understand. – Rishikesan Varudharajan Nov 15 '19 at 06:31
  • I've told you why it fails, and also how to fix it. What didn't you understand about that? – user207421 Nov 15 '19 at 06:47
  • I know other methods to read the data from stream using `while` loop As you said. but how can you read only a mentioned number of bytes alone from the stream? If i need to read only 1MB from a filestream of 5MB, how can you achieve this? – Rishikesan Varudharajan Nov 15 '19 at 06:52
  • 2
    Something like `while (remaining > 0 && (count = in.read(buffer, 0, (int)Math.min(remaining, buffer.length))) > 0) { out.write(buffer, 0, count); remaining -= count; }` where `remaining` is initially the total number of bytes to read. – user207421 Nov 15 '19 at 07:01
  • And if you're just writing the resulting byte array to a file, why the byte array? You can accomplish that without a `ByteArrayOutputStream` at all, and save yourself both time and space. – user207421 Nov 15 '19 at 08:35
  • My usecase is not to write data to a file for debugging purpose only I've used that. I need to send data split by multiple chunks. – Rishikesan Varudharajan Nov 15 '19 at 09:35
  • Could you explain, what do you mean under "resultant file on the filesystem seems broken"? Is your file binary, text? – SternK Nov 15 '19 at 15:38
  • @SternK It is broken because it contains extra junk, and the reason for that has already been given. – user207421 Nov 15 '19 at 22:33
  • @SternK I've tried some image files and they're broken. Due to extra junk bytes written, as explained by user207421 – Rishikesan Varudharajan Nov 18 '19 at 06:18

1 Answers1

1

My understanding of the problem statement

Read bytes number of bytes from the given InputStream in a ByteArrayOutputStream.
Finally, return a byte array.

Key observations

  • A lot of work is done to make sure bytes are read in chunks of 8KB.
    Also, the last remaining chunk of odd size is read separately.

  • A lot of work is also done to make sure we are reading from the correct offset.

My views

  • Unless we are reading a very large file (>10MB) I don't see a valid reason for reading in chunks of 8KB.

  • Let Java libraries do all the hard work of maintaining offset and making sure we don't read outside limits. Eg: We don't have to give offset, simply do inputStream.read(b) over and over, the next byte array of size b.length will be read. Similarly, we can simply write to outputStream.

Code

public byte[] readWrite(long bytes, InputStream in) throws IOException {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    byte[] buffer = new byte[(int)bytes];

    is.read(buffer);
    bos.write(buffer);

    return bos.toByteArray();
}

References

About InputStreams
Byte Array to Human Readable Format

Akash Yadav
  • 105
  • 7