unstacking io-related classes...

A

Andreas Leitgeb

Suppose I have some OutputStream(OS), which I want to
pass to a method that's supposed to write some data
onto it, and leave the write position right after the
newly written data.
Surely this is no problem, as long as the method uses
the stream directly - But what, if the method wants
e.g. a BufferedOutputStream(BOS) (or perhaps some
Writer) for its output?

If it wraps the OS into a BOS, then I see no way to cleanly
unwrap it later without accidentally closing the original OS.

I hope I'm missing something obvious and easy.
Or, is my usecase really so bizarre?

Alternatives/hacks that do not satisfy me:
Have the method write to an ByteArrayOutputStream wrapped to
the method's liking, and then copy the byte[] to the original
stream.
Add the BOS to a statically kept Collection and leave it there
till end of program (to prevent it's finalizer from closing the
original stream) ... gross hack and object-leak.
Create one's own subclass of FilterOutputStream that does not
close() the wrapped stream. Or does such a class already
exist? I didn't find any in java.io nor among the direct
subclasses of Closeable, FilterOutputStream and some more.

PS: I'm aware that in most cases, streamwrappers just are not
being unwrapped until close()-time, so in the majority of cases
this close()-behaviour is just fine.

PPS: as I stumbled over it: Why has "SequenceInputStream" not
been enhanced with an Iterator<? extends InputStream> taking
constructor, additionally to the one taking an Enumeration?
 
S

Sigfried

Andreas Leitgeb a écrit :
Suppose I have some OutputStream(OS), which I want to
pass to a method that's supposed to write some data
onto it, and leave the write position right after the
newly written data.
Surely this is no problem, as long as the method uses
the stream directly - But what, if the method wants
e.g. a BufferedOutputStream(BOS) (or perhaps some
Writer) for its output?

If it wraps the OS into a BOS, then I see no way to cleanly
unwrap it later without accidentally closing the original OS.

I hope I'm missing something obvious and easy.
Or, is my usecase really so bizarre?

Alternatives/hacks that do not satisfy me:
Have the method write to an ByteArrayOutputStream wrapped to
the method's liking, and then copy the byte[] to the original
stream.
Add the BOS to a statically kept Collection and leave it there
till end of program (to prevent it's finalizer from closing the
original stream) ... gross hack and object-leak.
Create one's own subclass of FilterOutputStream that does not
close() the wrapped stream. Or does such a class already
exist? I didn't find any in java.io nor among the direct
subclasses of Closeable, FilterOutputStream and some more.

PS: I'm aware that in most cases, streamwrappers just are not
being unwrapped until close()-time, so in the majority of cases
this close()-behaviour is just fine.

PPS: as I stumbled over it: Why has "SequenceInputStream" not
been enhanced with an Iterator<? extends InputStream> taking
constructor, additionally to the one taking an Enumeration?

If you do:

public void foo() {
try {
OutputStream os = ...;
otherMethod(new BufferedOutputStream(os));
// ...
} finally {
try { os.close(); } catch (IOException ignore) { }
}
}

os will be relased in the finally bloc. The GC will finalize the BOS,
close it, without having to close its internal reference to "os".
 
A

Andreas Leitgeb

Sigfried said:
Andreas Leitgeb a écrit :
public void foo() {
try {
OutputStream os = ...;
otherMethod(new BufferedOutputStream(os));

The GC *might* finalize and close the BOS (and thereby also os)
right here, before the very next line is reached.

Ok, I could also keep a reference to the BOS throughout the try-block,
but, anyway, I intended to leave the decision about wrapping the stream
(how, if at all) to the innards of otherMethod(OS).
 
M

Mark Space

Andreas said:
Suppose I have some OutputStream(OS), which I want to
pass to a method that's supposed to write some data
onto it, and leave the write position right after the
newly written data.
Surely this is no problem, as long as the method uses
the stream directly - But what, if the method wants
e.g. a BufferedOutputStream(BOS) (or perhaps some
Writer) for its output?

Modify the signature of the method. Make the caller pass in a
BufferOutputStream. Then you don't have to create one, or close the stream.
 
S

Sigfried

Andreas Leitgeb a écrit :
The GC *might* finalize and close the BOS (and thereby also os) right
here, before the very next line is reached.

From JDK source code, BOS doesn't have any finalize method.
 
A

Andreas Leitgeb

Patricia Shanahan said:
Andreas said:
[ OS: OutputStream, BOS: BufferedOS ]
If it wraps the OS into a BOS, then I see no way to cleanly
unwrap it later without accidentally closing the original OS.
How about flush(), not close(), the BufferedOutputStream, and then
forget about it?

Then the GC may call finalize() (too soon for my taste) on the wrapper,
which then calls "close()" on itself and on the wrapped stream.
It's that very last bit that I seek to prevent.

But thanks for caring.
 
A

Andreas Leitgeb

Sigfried said:
Andreas Leitgeb a écrit :

From JDK source code, BOS doesn't have any finalize method.

Ok, thanks! Now I finally spotted my flaw ...

Afterall, the only streams that really do close() in finalize()
appear to be File(In|Out)putStreams, and these don't matter here.

So, calling flush() and then forgetting the wrapper is indeed just the
solution I sought for.
 
A

Andreas Leitgeb

Andreas Leitgeb said:
Patricia Shanahan said:
Andreas said:
[ OS: OutputStream, BOS: BufferedOS ]
If it wraps the OS into a BOS, then I see no way to cleanly
unwrap it later without accidentally closing the original OS.
How about flush(), not close(), the BufferedOutputStream, and then
forget about it?

Forget my previous reply. That's, of course, how it works.

Somewhere in my backhead there was this piece of misinformation
about "finalize() does close() for all streams", which is only
true for File*Streams.

Thanks. Problem (in my head) solved.
 

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

Forum statistics

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

Latest Threads

Top