Search code examples
javafile-iofileoutputstreambufferedinputstream

BufferedOutputStream not throwing I/O exception


While working on BufferedOutputStream found it does not throw an IOException when we wrote on it after closing the stream.

To verify my result, i checked FileOutputStream found it is throwing IOException once we try to write on it after closing it.

public class Test {
    public static void main(String[] args) {
        try {
            // Created a byte[] barry1 barry2
            byte[] barry1 = { '1', '3' };
            byte[] barray2 = { '2', '4' };
            OutputStream os = new BufferedOutputStream(
                  new FileOutputStream("abc.txt", false));
            // Writing to stream
            os.write(barry1);
            os.close();
            os.write(barray2); // this suceeds - bug

            os = new FileOutputStream("abc.txt", true);
             //Writing to stream
            os.write(barry1);
            os.close();
            os.write(barray2); // crashes here, correct.
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Could some one help me on this, Why this behavior is different ?


Solution

  • While working on BufferedOutputStream found it does not throw an IOException when we wrote on it after closing the stream.

    The BufferedOutputStream code just doesn't have that sort of checking – but then neither does the FileOutputStream. In both cases, only when the IO is actually written to disk does the OS "throw" the IOException. It is not the Java code which is detecting that the stream has been closed. As an aside, this probably means that some native implementations don't throw at all.

    The reason why the FileOutputStream is throwing the exception on os.write(...), versus the BufferedOutputStream, is that it is writing the IO to the underlying native layer immediately. If you add a os.flush() call to the BufferedOutputStream after the os.write() then you will see the same exception because that forces its internal buffer to be written out.

    OutputStream os = new BufferedOutputStream(new FileOutputStream("abc.txt", false));
    os.write(barry1);
    os.close();
    os.write(barray2); // this suceeds – unfortunate behavior
    os.flush();  // adding this line throws an IOException
    

    In looking at the BufferedOutputStream's close() method (actually in the FilterOutputStream base class), you can see that the output stream is not set to null or anything:

    public void close() throws IOException {
        try {
          flush();
        } catch (IOException ignored) {
        }
        out.close();
    }
    

    I also don't like the fact that it is ignoring IOExceptions on close here. Wow. This tells me that we should always call flush() by hand before close() which is a pattern I specifically don't do.

    Now compare that code to the BufferedWriter.close():

    public void close() throws IOException {
        synchronized (lock) {
            if (out == null) {
                return;
            }
            try {
                flushBuffer();
            } finally {
                out.close();
                out = null;   // good doggie
                cb = null;
            }
        }
    }
    

    BufferedWriter.close() doesn't eat the exception and sets the delegated Writer to be null. Much better IMO.