私は、子プロセスと通信する必要がある、Rustの小さなncursesアプリケーションを作っています。私はすでにCommon Lispで書かれたプロトタイプを持っています。 gif hereは私がしたいことをうまく表示するでしょう。 CLはそのような小さなツールに膨大なメモリを使用しているので、私は書き直してみようとしています。Rustでブロックせずに子プロセスの出力を読み取るにはどうすればよいですか?
私はRust before(または他の低レベル言語)を使用していませんし、サブプロセスと対話する方法を理解するのにいくつか問題があります。
私が現在やっていることは大体これです:
プロセスを作成します。
let mut program = match Command::new(command) .args(arguments) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .spawn() { Ok(child) => child, Err(_) => { println!("Cannot run program '{}'.", command); return; }, };
を読み取って入力を処理し、無限(ユーザーが終了するまで)ループ、それを渡しますこのような出力を待ち受けて(画面に書き込む):
fn listen_for_output(program: &mut Child, output_viewer: &TextViewer) { match program.stdout { Some(ref mut out) => { let mut buf_string = String::new(); match out.read_to_string(&mut buf_string) { Ok(_) => output_viewer.append_string(buf_string), Err(_) => return, }; }, None => return, }; }
しかし、read_to_string
の呼び出しは、プロセスが終了するまでプログラムをブロックします。私が見ることができるからread_to_end
とread
もブロックするようです。私がすぐに終了するls
のようなものを実行しようとすると、それは動作しますが、python
またはsbcl
のように終了しないものでは、サブプロセスを手動で終了すると一度だけ続行されます。
編集:this answerに基づいて
、私はBufReader
を使用するようにコードを変更:
fn listen_for_output(program: &mut Child,
output_viewer: &TextViewer) {
match program.stdout.as_mut() {
Some(out) => {
let buf_reader = BufReader::new(out);
for line in buf_reader.lines() {
match line {
Ok(l) => {
output_viewer.append_string(l);
},
Err(_) => return,
};
}
},
None => return,
}
}
問題は依然として同じまましかし。利用可能なすべての行が読み込まれ、ブロックされます。ツールはどのプログラムでも動作するはずなので、読み込みを試みる前に出力が終了する時を推測する方法はありません。 BufReader
のいずれかのタイムアウトを設定する方法はありません。
役立つ説明をしてくれてありがとう。私はMIOを調べ、それがうまくいかない場合は別のスレッドを使用します。 – jkiiski