What happens internally when the outermost Stream is closed? - java

I know that to close all the internal and enclosing streams you can close the outermost Stream and it will take care of the enclosing Streams but do it waits to read and write data completely before closing the internal streams or just perform the required operations.
I just want to figure out what happens and how internal functions are called on the inner streams when we close an enclosing Stream? Just like in the below code
public static void serialize(Object obj, String fileName)
throws IOException {
FileOutputStream fos = new FileOutputStream(fileName);
BufferedOutputStream bos = new BufferedOutputStream(fos);
ObjectOutputStream oos = new ObjectOutputStream(bos);
bos.flush();
oos.writeObject(obj);
oos.close();
}
When I close the Object Stream will it wait for File Stream to perform its function?

Yes, if you close the ObjectOutputStream, all pending write operations will be performed.
That is because ObjectOutputStream calls innerStream.flush() wenn you call close() on it.
And BufferedOutputStream also calls innerStream.flush() in its own flush method.
All buffering stream classes I know do so.

Related

Closing a Socket with Streams

The following question I have is pretty straightforward.
Here is my code:
public class Protocol implements Runnable {
private SSLSocket socket = null;
private InputStream is = null;
private OutputStream os = null;
...
public Protocol(Socket s) {
socket = (SSLSocket)s;
is = socket.getInputStream();
os = socket.getOutputStream();
}
#Override
public void run() {
...
ping();
socket.close();
...
}
public void ping() {
BufferedWriter writer;
try {
writer = new BufferedWriter(new OutputStreamWriter(os));
writer.write("OK");
}
catch (IOException e) { System.out.println("ERROR: " + e.getLocalizedMessage()); }
finally { writer = null; }
}
I understand I didn't include a lot of source code, but this should be enough to answer the question. As you can see, in the "ping" method I have a BufferedWriter which I create to write an "OK" string to the remote source. Later on, I close the Socket.
So my simple question is this - From what I understand, since I close the socket, the chain should go like this:
Close socket ----> which closes is and os ----> closes writer
So, by closing the Socket, I am also closing and allowing the BufferedWriter to be freed by the GC. Am I understanding this correctly or doing something wrong? Is this true for all writers and readers that I initialize in other methods (i.e. BufferedInputStream). And by setting these variables null at the end of the method, am I helping the GC to distinguish between what should be freed? Or should I not do this?
Thanks!
From what I understand, since I close the socket, the chain should go like this:
Close socket ----> which closes is and os ----> closes writer
No. The BufferedWriter is wrapped around the socket output stream, but the socket doesn't know that. It has no way of closing it.
So, by closing the Socket, I am also closing and allowing the BufferedWriter to be freed by the GC.
No and no. The BufferedWriter is available for GC as soon as ping() returns, and it is never closed at all.
Am I understanding this correctly
No.
or doing something wrong?
Yes. You shouldn't create a new BufferedWriter per message. You should use the same one for the life of the socket, and close it instead of the socket. Similarly you should only use one input stream or Reader for the life of the socket. Otherwise you can lose data in their buffers.
Is this true for all writers and readers that I initialize in other methods (i.e. BufferedInputStream).
No.
And by setting these variables null at the end of the method, am I helping the GC to distinguish between what should be freed?
No. You are just wasting time and space. The method is about to exit anyway, so all its local variables disappear.
Or should I not do this?
You should not do any of it.

try-with behavior with implicit and explicit closeables

Are the following try-with blocks similar? Will the dataSocket.getOutputStream() be closed in both cases?
a)
try (Socket dataSocket = new Socket(...);
OutputStream socketStream = dataSocket.getOutputStream();
BufferedOutputStream outputStream = new BufferedOutputStream(socketStream)
) {.....}
b)
try (Socket dataSocket = new Socket(...);
BufferedOutputStream outputStream = new BufferedOutputStream(dataSocket.getOutputStream())
) {.....}
Note. in b) there is no explicit variable for dataSocket.getOutputStream(), in a) we have socketStream.
According to BufferedOutputStream JavaDoc,
Closes this output stream and releases any system resources associated with the stream.
Closing outputStream would close the underlying outputstream. This is also proven in the source code of BufferedOutputStream's close() method.
public void close() throws IOException {
try {
flush();
} catch (IOException ignored) {
}
out.close();
}
Yes, it will be closed in both cases. Even using only Socket sentence, they should be closed. When socket is closed, streams are closed. Anyway, I prefer explicity add Streams declaration on try-with structure.

Why is ObjectInputStream readObject() throwing EOF exception

I am stuck with this very strange problem. In the client I am passing in objects like
try{
oos.writeObject(new GameStartSerializedObject());
oos.flush();
}
catch(Exception e){
e.printStackTrace();
}
and in the server I am reading the object
try{
//Its my turn
thrown_message = player_reader.readObject();
}
catch(Exception e){
My question is why am i getting EOF exception. My understanding of object input stream is when i call readObject() i should block until i get an object so how does it know if the eof is reached? Please help!
This is how I create object streams
ois = new ObjectInputStream(socket.getInputStream());
oos = new ObjectOutputStream(socket.getOutputStream());
oos.flush();
Also, after i write object and flush should i close the stream. I am not closing it since the objects are written pretty regularly from different parts of the code one after another.
The peer has closed the connection. Ergo there are no more objects to read. Ergo you have reached the end of the stream. Ergo readObject() throws EOFException.

Does a PrintWriter / PrintStream need to be flushed?

I'd like to use a PrintWriter or PrintStream to write formatted strings out to an outputstream (for which I have no control over the creation). However flushing the underlying OutputStream has a big performance hit.
Does a PrintWriter / PrintStream need to be flushed.
If I need to flush the PrintStream / PrintWriter; can I do so without flushing the underlying OutputStream, or will I need to create a "flush protecter" OutputStream to wrap the underlying stream?
To try to be a little clearer on this I want to implement
public void writeSomeString(OutputStream foo);
But this method may be called many times for the same OutputStream (foo). Each call will have to construct its own PrintWriter. I know it's ugly to do so but I have no control over the interface or the creation of foo.
I'm trying to avoid each method having to flush foo just to flush its own PrintWriter / PrintStream.
So I want to:
public void writeSomeString(OutputStream foo) {
PrintStream s = new PrintStream(foo);
s.println("bar");
// other code
}
I want to completely avoid this method flushing foo
PrintWriter needs to be flushed in the following condition:
ServerSocket s = new ServerSocket(4444);
Socket incoming = s.accept();
OutputStream output = s.getOutputStream();
PrintWriter pw = new PrintWriter(output,true);
System.out.println(pw.write(new Scanner(System.in).nextLine()));
2nd parameter in PrintWriter constructor is flush which accepts boolean datatype, we need to flush the data, so it gets thrown on the Console even if the buffer is not full.

BufferedReader to BufferedWriter

How can I obtain a BufferedWriter from a BufferedReader?
I'd like to be able to do something like this:
BufferedReader read = new BufferedReader(new InputStreamReader(...));
BufferedWriter write = new BufferedWriter(read);
You can use the following from Apache commons io:
IOUtils.copy(reader, writer);
site here
JAVA 9 Updates
Since Java 9, Reader provides a method called transferTo with the following signature:
public long transferTo(Writer out) throws IOException
As the documentation states, transferTo will:
Reads all characters from this reader and writes the characters to the given writer in the order that they are read. On return, this reader will be at end of the stream. This method does not close either reader or writer.
This method may block indefinitely reading from the reader, or writing to the writer. The behavior for the case where the reader and/or writer is asynchronously closed , or the thread interrupted during the transfer, is highly reader and writer specific, and therefore not specified.
If an I/O error occurs reading from the reader or writing to the writer, then it may do so after some characters have been read or written. Consequently the reader may not be at end of the stream and one, or both, streams may be in an inconsistent state. It is strongly recommended that both streams be promptly closed if an I/O error occurs.
So in order to write contents of a Java Reader to a Writer, you can write:
reader.transferTo(writer);
If you want to know what happens:
All input from the reader is copied to the inputstream
Something similar too:
private final void copyInputStream( InputStreamReader in, OutputStreamWriter out ) throws IOException
{
char[] buffer=new char[1024];
int len;
while ( ( len=in.read(buffer) ) >= 0 )
{
out.write(buffer, 0, len);
}
}
More on input and output on The Really big Index
BufferedWriter constructor is not overloaded for accept readers right? what Buhb said was correct.
BufferedWriter writer = new BufferedWriter(
new FileWriter("filename_towrite"));
IOUtils.copy(new InputStreamReader(new FileInputStream("filename_toread")), writer);
writer.flush();
writer.close();
You could use Piped Read/Writers (link). This is exactly what they're designed for. Not sure you could retcon them onto an existing buffered reader you got passed tho'. You'd have to construct the buf reader yourself around it deliberately.

Categories