How can I read non-blocking from stdin?

后端 未结 3 843
南笙
南笙 2020-12-17 16:17

Is there a way to check whether data is available on stdin in Rust, or to do a read that returns immediately with the currently available data?

My goal

相关标签:
3条回答
  • 2020-12-17 16:51

    You could also potentially look at using ncurses (also on crates.io) which would allow you read in raw mode. There are a few examples in the Github repository which show how to do this.

    0 讨论(0)
  • Most operating systems default to work with the standard input and output in a blocking way. No wonder then that the Rust library follows in stead.

    To read from a blocking stream in a non-blocking way you might create a separate thread, so that the extra thread blocks instead of the main one. Checking whether a blocking file descriptor produced some input is similar: spawn a thread, make it read the data, check whether it produced any data so far.

    Here's a piece of code that I use with a similar goal of processing a pipe output interactively and that can hopefully serve as an example. It sends the data over a channel, which supports the try_recv method - allowing you to check whether the data is available or not.

    Someone has told me that mio might be used to read from a pipe in a non-blocking way, so you might want to check it out too. I suspect that passing the stdin file descriptor (0) to PipeReader::from_fd should just work.

    0 讨论(0)
  • 2020-12-17 17:06

    Converting OP's comment into an answer:

    You can spawn a thread and send data over a channel. You can then poll that channel in the main thread using try_recv.

    use std::io;
    use std::sync::mpsc;
    use std::sync::mpsc::Receiver;
    use std::sync::mpsc::TryRecvError;
    use std::{thread, time};
    
    fn main() {
        let stdin_channel = spawn_stdin_channel();
        loop {
            match stdin_channel.try_recv() {
                Ok(key) => println!("Received: {}", key),
                Err(TryRecvError::Empty) => println!("Channel empty"),
                Err(TryRecvError::Disconnected) => panic!("Channel disconnected"),
            }
            sleep(1000);
        }
    }
    
    fn spawn_stdin_channel() -> Receiver<String> {
        let (tx, rx) = mpsc::channel::<String>();
        thread::spawn(move || loop {
            let mut buffer = String::new();
            io::stdin().read_line(&mut buffer).unwrap();
            tx.send(buffer).unwrap();
        });
        rx
    }
    
    fn sleep(millis: u64) {
        let duration = time::Duration::from_millis(millis);
        thread::sleep(duration);
    }
    
    0 讨论(0)
提交回复
热议问题