Java: InputStreams and OutputStreams being shared

2019-07-24 15:04发布

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?

3条回答
戒情不戒烟
2楼-- · 2019-07-24 15:19

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.

查看更多
萌系小妹纸
3楼-- · 2019-07-24 15:31

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!

查看更多
孤傲高冷的网名
4楼-- · 2019-07-24 15:42

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
查看更多
登录 后发表回答