Why should close() close the underlying stream?

X

Xiao Ma

A stream may have an underlying stream. For example,
FileOutputStream fos = new FileOutputStream("foo");
BufferedOutputStream bos = new BufferedOutputStream(fos);
fos is the underlying stream for bos.

Now if I call bos.close(), it will also close its underlying stream.
Why should the underlying stream be closed? I can think of some cases
where I want to continue to write to the underlying output stream
after I close the "outer" output stream.

I know it's useful if people do
BufferedOutputStream bos = new BufferedOutputStream(new
FileOutputStream("foo"));
and you don't have a handle on the underlying stream. But you can
always define a variable for the underlying stream.

I have a method that allows the caller to pass in an output stream.
Then I want to use a BufferedOutputStream to write to it. After that,
I should close the BufferedOutputStream before exiting the method. But
that closes the output stream passed in by the caller and the caller
can no longer write to it. For example,
void foo(OutputStream out) {
try {
BufferedOutputStream bout = new BufferedOutputStream(out);
bout.write(blahblah);
}
finally {
bout.close(); // I should close any stream I created but
this closes the underlying stream, too.
}
}
 
L

Lew

Xiao said:
A stream may have an underlying stream. For example,
FileOutputStream fos = new FileOutputStream("foo");
BufferedOutputStream bos = new BufferedOutputStream(fos);
fos is the underlying stream for bos.

Now if I call bos.close(), it will also close its underlying stream.
Why should the underlying stream be closed? I can think of some cases
where I want to continue to write to the underlying output stream
after I close the "outer" output stream.

If you don't want the stream closed, don't close the stream.
 
E

Eric Sosman

Xiao said:
A stream may have an underlying stream. For example,
FileOutputStream fos = new FileOutputStream("foo");
BufferedOutputStream bos = new BufferedOutputStream(fos);
fos is the underlying stream for bos.

Now if I call bos.close(), it will also close its underlying stream.
Why should the underlying stream be closed? I can think of some cases
where I want to continue to write to the underlying output stream
after I close the "outer" output stream.
[...]

The people who designed java.io apparently felt that
such cases were a small minority, and chose to simplify
matters for what they considered the much more common case.

If you need the "one at a time" discipline, you can
get it without much work. Just extend FileOutputStream (or
whatever) with a class of your own that inherits almost all
its methods from the superclass, but overrides close() and
ignores it. If desired you could add a reallyClose() method
that forwards to super.close(), and/or a getActualStream()
method that returns the superclass instance.
 
Z

Zig

A stream may have an underlying stream. For example,
FileOutputStream fos = new FileOutputStream("foo");
BufferedOutputStream bos = new BufferedOutputStream(fos);
fos is the underlying stream for bos.

Now if I call bos.close(), it will also close its underlying stream.
Why should the underlying stream be closed? I can think of some cases
where I want to continue to write to the underlying output stream
after I close the "outer" output stream.

Because the streams in java.io are simple streams - the concept of
segregating streams and embedding multiple sub-streams are much higher
abstraction that must be implemented outside of the java.io package.

Think of it this way: once you have written your stream, if you don't want
to close the underlying stream, how do you propose to write the
corresponding read(InputStream) method to read that data back in? A simple
BufferedInputStream is unbounded, so it will auto-read into the source
stream past the point that your BufferedOutputStream closed it.
I know it's useful if people do
BufferedOutputStream bos = new BufferedOutputStream(new
FileOutputStream("foo"));
and you don't have a handle on the underlying stream. But you can
always define a variable for the underlying stream.

I have a method that allows the caller to pass in an output stream.
Then I want to use a BufferedOutputStream to write to it. After that,
I should close the BufferedOutputStream before exiting the method. But
that closes the output stream passed in by the caller and the caller
can no longer write to it. For example,
void foo(OutputStream out) {
try {
BufferedOutputStream bout = new BufferedOutputStream(out);
bout.write(blahblah);
}
finally {
bout.close(); // I should close any stream I created but
this closes the underlying stream, too.
}
}

for BufferedOutputStream, a simple flush() will suffice. If you've got
something fancier that needs to write a terminator, or has special
handling for the last block of data, consider my comments above.

HTH,

-Zig
 
D

Daniel Pitts

Eric said:
Xiao said:
A stream may have an underlying stream. For example,
FileOutputStream fos = new FileOutputStream("foo");
BufferedOutputStream bos = new BufferedOutputStream(fos);
fos is the underlying stream for bos.

Now if I call bos.close(), it will also close its underlying stream.
Why should the underlying stream be closed? I can think of some cases
where I want to continue to write to the underlying output stream
after I close the "outer" output stream.
[...]

The people who designed java.io apparently felt that
such cases were a small minority, and chose to simplify
matters for what they considered the much more common case.

If you need the "one at a time" discipline, you can
get it without much work. Just extend FileOutputStream (or
whatever) with a class of your own that inherits almost all
its methods from the superclass, but overrides close() and
ignores it. If desired you could add a reallyClose() method
that forwards to super.close(), and/or a getActualStream()
method that returns the superclass instance.
You can't return a superclass instance, however you probably should use
inheritance here anyway. You should probably implement an OutputStream
that delegates to another OutputStream except for close().

Using that approach, you could use reallyClose() or getDelegate().close()

Although, as has been mentioned, usually if you close a stream, you
really DO want to close the underlying streams too.
 
L

Lew

Daniel said:
Although, as has been mentioned, usually if you close a stream, you
really DO want to close the underlying streams too.

I can't seem to think of a use case for not closing the underlying stream.
Every time I think I have one, it's simpler not to close the stream at all.
 
M

Mike Schilling

Zig said:
for BufferedOutputStream, a simple flush() will suffice.

That's true for almost all output filter streams and writers:
BufferedOutputStream, DataOutputStream, etc. When you're done with the
filter, you can just flush() it and stop using it.

The anaologus situation with input filter streams and readers is a problem;
having attached, say, a DataInputStream to an InputStream, it's not safe to
read a few data values and then return to reading the underlying stream.
You can't in general tell how many bytes have been read and buffered from
the underlying stream, and there's no call to push all of it back. In
general, this problem is intractable.
 
S

Silvio Bierman

Lew said:
I can't seem to think of a use case for not closing the underlying
stream. Every time I think I have one, it's simpler not to close the
stream at all.

Hello Lew,

I had some use cases for this in the past. I was writing a compound XML
doc to an OutputStream (HTTP response) and needed a library to write an
XML representation of one of it's object instances somewhere in to an
element in the total XML doc.
Unfortunately the library insisted on closing the stream that I passed
it. Off course that would prevent me to complete the surrounding XML
document.
I needed to be able to pass it an OutputStream that would just extend my
current OutputStream and then just flush it when it was done. Simple
enough, off course.

Just create a wrapping OutputStream that only calls wrapped.flush() in
its close method.

Silvio Bierman
 
R

Roedy Green

Now if I call bos.close(), it will also close its underlying stream.
Why should the underlying stream be closed?

because after you have composed your stack of i/o processors, it
behaves like a single unit. OO thinking is that you are not supposed
to be aware of how code is constructed, only the final facade.

The practical reason is 99.9% of the time you want all the components
closed.
 
E

Eric Sosman

Daniel said:
Eric said:
[...] If desired you could add a reallyClose() method
that forwards to super.close(), and/or a getActualStream()
method that returns the superclass instance.
You can't return a superclass instance, [...]

Gugghh! You're right, of course; sorry for the red
herring.
 
E

Eric Sosman

Silvio said:
Hello Lew,

I had some use cases for this in the past. I was writing a compound XML
doc to an OutputStream (HTTP response) and needed a library to write an
XML representation of one of it's object instances somewhere in to an
element in the total XML doc.
Unfortunately the library insisted on closing the stream that I passed
it. Off course that would prevent me to complete the surrounding XML
document.
I needed to be able to pass it an OutputStream that would just extend my
current OutputStream and then just flush it when it was done. Simple
enough, off course.

Just create a wrapping OutputStream that only calls wrapped.flush() in
its close method.

Another approach might be to use a SequenceInputStream.
You would pass individual PipedOutputStream objects to the
libraries that write and close, connecting their other ends
to PipedInputStreams that feed the SIS, which you'd then
just read and copy to the final output.

Or if the library doesn't generate "too much" data you
could hand it a ByteArrayOutputStream, let it be written and
closed, and then dump its data to your actual output.

There may be a couple dozen ways to skin this cat ...
 
L

Lew

That's a bad library, not an argument for keeping the underlying stream open.
Libraries should not close streams passed into them.
 
?

=?ISO-8859-1?Q?Arne_Vajh=F8j?=

Eric said:
Daniel said:
Eric said:
[...] If desired you could add a reallyClose() method
that forwards to super.close(), and/or a getActualStream()
method that returns the superclass instance.
You can't return a superclass instance, [...]

Gugghh! You're right, of course; sorry for the red
herring.

Something similar can be made to work.

package october;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io_OutputStream;
import java.io.PrintStream;

public class NonClosingStream extends OutputStream {
private OutputStream real;
public NonClosingStream(OutputStream real) {
this.real = real;
}
public void close() throws IOException {
// ignore
}
public void realclose() throws IOException {
real.close();
}
public boolean equals(Object obj) {
return real.equals(obj);
}
public void flush() throws IOException {
real.flush();
}
public int hashCode() {
return real.hashCode();
}
public String toString() {
return real.toString();
}
public void write(byte[] b, int off, int len) throws IOException {
real.write(b, off, len);
}
public void write(byte[] b) throws IOException {
real.write(b);
}
public void write(int b) throws IOException {
real.write(b);
}
public static void main(String[] args) throws IOException {
// OutputStream os = new FileOutputStream("C:\\z.z");
NonClosingStream os = new NonClosingStream(new
FileOutputStream("C:\\z.z"));
PrintStream ps = new PrintStream(os);
ps.println("Hello");
ps.close();
PrintStream ps2 = new PrintStream(os);
ps2.println("Hello");
ps2.close();
os.realclose();
}
}

Arne
 
G

Guest

Lew said:
I can't seem to think of a use case for not closing the underlying
stream. Every time I think I have one, it's simpler not to close the
stream at all.

A very similar question showed up in the C# group and it turned
out that Jon Skeet had a wrapper class for it on his web site.

Arne
 
E

Esmond Pitt

Arne said:
Something similar can be made to work.

public class NonClosingStream extends OutputStream {

It's *much* simpler than that:

public class NonClosingStream extends FilterOutputStream {
public NonClosingStream(OutputStream out) { super(out); }
public void close() {}
}
 
Z

Zig

It's *much* simpler than that:

public class NonClosingStream extends FilterOutputStream {
public NonClosingStream(OutputStream out) { super(out); }
public void close() {}
}

While that will actually work, pushing data through that stream is
extremely inefficient.

While FilterInputStream.read(byte[], int, int) passes through the buffered
read to the underlying stream, FilterOutputStream.write(byte[], int, int)
breaks the write into unbuffered byte-by-byte writes.

So, you *really* want

public class NonClosingStream extends FilterOutputStream {
public NonClosingStream(OutputStream out) { super(out); }
public void write(byte[] buf, int off, int len) throws IOException {
out.write(buf, off, len);
}
public void close() {}
}

Just another fun qwerk from classes designed back in the Java 1.0 days. As
an alternative, check out org.apache.commons.io.input.ProxyInputStream.
The Apache Commons IO library seems to have tried to learn from these
little problems.

HTH,

-Zig
 
?

=?ISO-8859-15?Q?Arne_Vajh=F8j?=

Zig said:
It's *much* simpler than that:

public class NonClosingStream extends FilterOutputStream {
public NonClosingStream(OutputStream out) { super(out); }
public void close() {}
}

While that will actually work, pushing data through that stream is
extremely inefficient.

While FilterInputStream.read(byte[], int, int) passes through the
buffered read to the underlying stream, FilterOutputStream.write(byte[],
int, int) breaks the write into unbuffered byte-by-byte writes.

So, you *really* want

public class NonClosingStream extends FilterOutputStream {
public NonClosingStream(OutputStream out) { super(out); }
public void write(byte[] buf, int off, int len) throws IOException {
out.write(buf, off, len);
}
public void close() {}
}

Just another fun qwerk from classes designed back in the Java 1.0 days.
As an alternative, check out
org.apache.commons.io.input.ProxyInputStream. The Apache Commons IO
library seems to have tried to learn from these little problems.

Yet another example of that extends can tie your code to the internals
of the class you are extending.

Not that I was aware - I did not use FilterOutputStream, because I did
not know about the class !

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top