Tony R
Tony R

Reputation: 11524

How to asynchronously read stdin?

Is there an elegant way to fire an event when characters are available from System.in? I'd like to avoid polling InputStream.available().

Upvotes: 3

Views: 3854

Answers (5)

krico
krico

Reputation: 5728

new Thread(){

   public void run() {
      while(System.in.get()){
   }

}.start();

Upvotes: 0

Jack
Jack

Reputation: 133567

If you want something elegant you could easily implement an ObservableInputStream which accepts a Listener that gets warned about availability of data but you will have to implement it with an inner thread that periodically checks for data and call the listener in case.

Think about the fact that streams aren't supposed to be used as object that send small packets but a continuous stream of bytes, that's why this approach would work only if the data that is given to the input stream doesn't effectively arrives too often (otherwise it would keep calling the listener ad libitum). In addition you will have to care about consistency, if data arrive when something is already available and the listener is warned then something can take all the bytes (which you should place in a temporary buffer) but if there's more data that just arrived you should decide how to handle (give it together with buffer, place in buffer and call listener again, etc)

Upvotes: 0

salezica
salezica

Reputation: 76909

Very generally speaking:

If you already have an event reactor running, create a thread and have it block on read(). When there's data available, have that thread enqueue an event for the reactor to process. If you can't do this, most event reactors provide an InvokeLater, or CallLater method, for you to run some code in the event processing thread.

After notifying or scheduling a function call, go back to blocking on read().

Upvotes: 0

aioobe
aioobe

Reputation: 420951

You would have to create a separate thread that blocks in read until something is available.

If you don't want to actually eat up the input, you would have to wrap it with an internal buffer, read into the buffer, shout, and when asked for the input, give back data from the buffer.

You could solve it like this:

InputStream stdin = System.in;

// Create a wrapper (with it's own dedicated read-thread)
MyListenableInputStream listenableInputStream =
        new MyListenableInputStream(stdin);

// Update System.in with something more useful.
System.setIn(listenableInputStream);

Upvotes: 4

JOTN
JOTN

Reputation: 6317

Sure...start a thread that blocks on the input and then calls your event method when it gets something.

Upvotes: 2

Related Questions