使用 BufReader 连续处理子进程的输出字节

Continuously process child process' outputs byte for byte with a BufReader

我正在尝试与外部命令(在本例中为 exiftool)交互并逐字节读取输出,如下例所示。 虽然如果我愿意首先读入所有输出并等待子进程完成,我可以让它工作,但使用 BufReader 似乎会导致无限期地等待第一个字节。我使用 this example 作为使用 BufReader 访问标准输出的参考。

use std::io::{Write, Read};
use std::process::{Command, Stdio, ChildStdin, ChildStdout};

fn main() {
    let mut child = Command::new("exiftool")
        .arg("-@") // "Read command line options from file"
        .arg("-") // use stdin for -@
        .arg("-q") // "quiet processing" (only send image data to stdout)
        .arg("-previewImage") // for extracting thumbnails
        .arg("-b") // "Output metadata in binary format"
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn().unwrap();

    {
        // Pass input file names via stdin
        let stdin: &mut ChildStdin = child.stdin.as_mut().unwrap();
        stdin.write_all("IMG_1709.CR2".as_bytes()).unwrap();
        // Leave scope:
        // "When an instance of ChildStdin is dropped, the ChildStdin’s underlying file handle will
        // be closed."
    }

    // This doesn't work:
    let stdout: ChildStdout = child.stdout.take().unwrap();
    let reader = std::io::BufReader::new(stdout);
    for (byte_i, byte_value) in reader.bytes().enumerate() {
        // This line is never printed and the program doesn't seem to terminate:
        println!("Obtained byte {}: {}", byte_i, byte_value.unwrap());
        // …
        break;
    }

    // This works:
    let output = child.wait_with_output().unwrap();
    for (byte_i, byte_value) in output.stdout.iter().enumerate() {
        println!("Obtained byte {}: {}", byte_i, byte_value);
        // …
        break;
    }
}

您没有关闭 child 的标准输入。您的 stdin 变量是一个可变引用,删除它对引用的 ChildStdin.

没有影响

使用child.stdin.take()代替child.stdin.as_mut()

    {
        // Pass input file names via stdin
        let stdin: ChildStdin = child.stdin.take().unwrap();
        stdin.write_all("IMG_1709.CR2".as_bytes()).unwrap();
        // Leave scope:
        // "When an instance of ChildStdin is dropped, the ChildStdin’s underlying file handle will
        // be closed."
    }