Avoid loading files into byte arrays or buffers in memory without some kind of limit.

The system will quickly run out of memory if the file loaded in happens to be larger than expected.

The following example function reads a file from disk and returns it as a byte array:

public static byte[] getFileAsBytes(File theFile) throws IOException
{
    FileInputStream in = null;
    try
    {
        byte[] buf = new byte[(int)theFile.length()];
        in = new FileInputStream(theFile);
        int totalBytesRead = 0;
        int bytesRead = 0;
        while (bytesRead != -1)
        {
            bytesRead = in.read(buf,totalBytesRead,in.available());
            totalBytesRead += bytesRead;
        }
        return buf;
    }
    finally
    {
     if (in != null) try {in.close();} catch (IOException e) {logger.error(e);}
    }
}     

Unfortunately the design is such that the byte array buffer needs to be allocated to the size of the file. When the code was being tested, the file being loaded in was small so the function never failed. But one customer had a 40 megabyte file, which caused an OutOfMemoryError and terminated the application.

There are some alternatives:

1) If the file is being loaded simply so it can be written somewhere else, copy the incoming stream to the destination output stream directly, chunk by chunk.

2) Read the file in small pieces, parsing each as you go, so it's not necessary to load the whole file at once.

3) Put some limits on the size of the file that can be passed in, and handle it elegantly.

Trap: File related methods that require byte[] parameters can be a sign of potential memory management problems unless the application is completely in control of the files being processed.  A byte array can be used when absolutely sure that the file being loaded in was created by your own application or will always be of a small size.

blog comments powered by Disqus