3

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 ?

Gray
  • 115,027
  • 24
  • 293
  • 354
T-Bag
  • 10,916
  • 3
  • 54
  • 118

3 Answers3

5

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.

Gray
  • 115,027
  • 24
  • 293
  • 354
  • +1 to this answer. I had same doubt until I tried to call outputsteam.flush(). That call immediately threw IOException when outputstream is closed. – AlienOnEarth Feb 14 '19 at 06:58
0

Because BufferedOutputStream writes bytes to its internal byte buffer, then when invoked writes to the underlying ouput stream, so if call flush after the os.write(c);, it will throw the exception, but here you try to write to the file stream directly after it was closed, hence the exception, no surprise here

Trash Can
  • 6,608
  • 5
  • 24
  • 38
  • 1
    No, I think it's still surprising that writing to the `BufferedOutputStream` when *that* is closed (not the `FileOutputStream`) doesn't throw an exception. I could understand if the OP were closing the `FileOutputStream` underneath, but I'd expect `BufferedOutputStream` to have a check as well. – Jon Skeet Mar 29 '17 at 05:46
  • 1
    Woow a favour comment from @JonSkeet ... :) Sir please check – T-Bag Mar 29 '17 at 05:48
0

After checking the JDK code found that ensureOpen() method that throws an IOException with a detail message of "Stream closed"is missing in BufferedOutputStream. From my understanding this must be there.

T-Bag
  • 10,916
  • 3
  • 54
  • 118