Can I share an InputStream
or OutputStream
?
For example, let's say I first have:
DataInputStream incoming = new DataInputStream(socket.getInputStream()));
...incoming
being an object variable. Later on I temporarily do:
BufferedReader dataReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
I understand that the stream is concrete and reading from it will consume its input, no matter from where it's done... But after doing the above, can I still access both incoming
and dataReader
simultaneously or is the InputStream
just connected to ONE object and therefore incoming
loses its input once I declare dataReader
? I understand that if I close the dataReader
then I will close the socket as well and I will refrain from this but I'm wondering whether I need to "reclaim" the InputStream
somehow to incoming
after having "transferred" it to dataReader
? Do I have to do:
incoming = new DataInputStream(socket.getInputStream());
again after this whole operation?
You are using a teaspoon and a shovel to move dirt from a hole.
I understand that the stream is concrete and reading from it will
consume its input, no matter from where it's done
Correct. The teaspoon and shovel both move dirt from the hole. If you are removing dirt asynchronously (i.e. concurrently) you could get into fights about who has what dirt - so use concurrent construct to provide mutually exclusive access. If access is not concurrent, in other words ...
1) move one or more teaspoons of dirt from the hole
2) move one or more shovels of dirt from the hole
3) move one or more teaspoons of dirt from the hole
...
No problem. Teaspoon and shovel both remove dirt. But once dirt gets removed, it's removed, they do not get the same dirt. Hope this helps. Let's start shovelling, I'll use the teaspoon. :)
As fast-reflexes found, be very careful about sharing streams, particularly buffered readers since they can gobble up a lot more bytes off the stream than they need, so when you go back to your other input stream (or reader) it may look like a whole bunch of bytes have been skipped.
Proof you can read from same input stream:
import java.io.*;
public class w {
public static void main(String[] args) throws Exception {
InputStream input = new FileInputStream("myfile.txt");
DataInputStream b = new DataInputStream(input);
int data, count = 0;
// read first 20 characters with DataInputStream
while ((data = b.read()) != -1 && ++count < 20) {
System.out.print((char) data);
}
// if prematurely interrupted because of count
// then spit out last char grabbed
if (data != -1)
System.out.print((char) data);
// read remainder of file with underlying InputStream
while ((data = input.read()) != -1) {
System.out.print((char) data);
}
b.close();
}
}
Input file:
hello OP
this is
a file
with some basic text
to see how this
works when moving dirt
from a hole with a teaspoon
and a shovel
Output:
hello OP
this is
a file
with some basic text
to see how this
works when moving dirt
from a hole with a teaspoon
and a shovel
Proof to show BufferedReader is NOT gauranteed to work as it gobbles up lots of chars from the stream:
import java.io.*;
public class w {
public static void main(String[] args) throws Exception {
InputStream input = new FileInputStream("myfile.txt");
BufferedReader b = new BufferedReader(new InputStreamReader(input));
// read three lines with BufferedReader
String line;
for (int i = 0; (line = b.readLine()) != null && i < 3; ++i) {
System.out.println(line);
}
// read remainder of file with underlying InputStream
int data;
while ((data = input.read()) != -1) {
System.out.print((char) data);
}
b.close();
}
}
Input file (same as above):
hello OP
this is
a file
with some basic text
to see how this
works when moving dirt
from a hole with a teaspoon
and a shovel
Output:
hello OP
this is
a file
This will be disastrous. Both streams will have corrupted data. How could Java possibly know which data to send to which Stream?
If you need to do two different things with the same data, you're better off storing it somewhere (possibly copying it into two Queue<String>
), and then reading it that way.
Ok, I solved this myself.. interesting links:
http://www.coderanch.com/t/276168//java/InputStream-multiple-Readers
Multiple readers for InputStream in Java
Basically... the InputStream
can be connected to multiple objects reading from it and consuming it. However, a BufferedReader
reads ahead, so when involving one of those, it might be a good idea to implement some sort of signal when you're switching from for example a BufferedReader
to a DataInputStream
(that is you want to use the DataInputStream
to process the InputStream
all of a sudden instead of the BufferedReader
). Therefore I stop sending data to the InputStream
once I know that all data has been sent that is for the BufferedReader
to handle. After this, I wait for the other part to process what it should with the BufferedReader
. It then sends a signal to show that it's ready for new input. The sending part should be blocking until it receives the signal input and then it can start sending data again. If I don't use the BufferedReader
after this point, it won't have a chance to buffer up all the input and "steal" it from the DataInputStream
and everything works very well :) But be careful, one read operation from the BufferedReader
and you will be back in the same situation... Good to know!