如何将可执行二进制文件的输出写入内存而不是磁盘

我得到了一个像下面这样工作的二进制文件:


> ./my_bin raw.avi output_file.avi

output_file.avi是我想要的,当作业成功时,终端会打印一些详细信息,例如:


版权所有 2022 Company Inc... 成功。


我想在我的代码中运行这个命令并将其重定向output_file.avi到某个字节数组,这样我就不必从磁盘读取它并删除它。我的方法类似于下面的 Golang 代码片段:


func wrongOne(stdin []byte) ([]byte, error) {

    inBuf := bytes.NewBuffer(stdin)

    outBuf := bytes.NewBuffer(nil)

    cmd := exec.Command("./my_bin", "/dev/stdin", "/dev/stdout")

    cmd.Stdin = inBuf

    cmd.Stdout = outBuf

    err := cmd.Run()

    if err != nil {

        return nil, err

    }

    return outBuf.Bytes(), nil // wrong

}

但是,返回的字节数组比下面的方法长,这会导致 MD5 检查失败。


func correctOne(stdin []byte) ([]byte, error) {

    inBuf := bytes.NewBuffer(stdin)

    cmd := exec.Command("./my_bin", "/dev/stdin", "output_file")

    cmd.Stdin = inBuf

    err := cmd.Run()

    if err != nil {

        return nil, err

    }

    return os.ReadFile("output_file")

}

该wrongOne功能可以修改为以下代码是正确的:


func modifiedWrongOne(stdin []byte) ([]byte, error) {

    inBuf := bytes.NewBuffer(stdin)

    outBuf := bytes.NewBuffer(nil)

    cmd := exec.Command("./my_bin", "/dev/stdin", "/dev/stdout")

    cmd.Stdin = inBuf

    cmd.Stdout = outBuf

    err := cmd.Run()

    if err != nil {

        return nil, err

    }

    correct, _ := correctOne(stdin)

    return outBuf.Bytes()[:len(correct)], nil // diff

}

我假设输出详细信息包含在 中,/dev/stdout因此该wrongOne函数不起作用。IE,


wrongOne= 的输出+ correctOne[]byte{"Copyright 2022 Company Inc... Success."}


有没有什么解决方案可以output_file.avi在不将其保存为文件并从磁盘读取的情况下获取管道?谢谢!


慕桂英3389331
浏览 121回答 2
2回答

HUH函数

该命令将版权声明写入标准输出。为避免将版权声明与输出文件混在一起,请使用 /dev/stdout 以外的文件作为输出文件。下面的函数使用Cmd.ExtraFiles将管道连接到子进程中的 fd 3。该函数将数据从管道复制到字节缓冲区,并将这些字节返回给调用者。func otherOne(stdin []byte) ([]byte, error) {    r, w, err := os.Pipe()    if err != nil {        return nil, err    }    defer r.Close()    defer w.Close()    cmd := exec.Command("./my_bin", "/dev/stdin", "/dev/fd/3")    cmd.Stdin = bytes.NewReader(stdin)    cmd.ExtraFiles = []*os.File{w} // The first file is fd 3.    if err := cmd.Start(); err != nil {        return nil, err    }    w.Close()    var outbuf bytes.Buffer    if _, err := io.Copy(&outbuf, r); err != nil {        return nil, err    }    if err := cmd.Wait(); err != nil {        return nil, err    }    return outbuf.Bytes(), nil}

侃侃无极

几个月后,我想出了另一种方法来解决这个问题。基本思想与Cerise类似,即/dev/fd/3用于重定向输出文件。之后,我们分别重定向/dev/fd/3到/dev/stdout, verbose log 到/dev/stderr by 3>&1, 1>&2。添加了一个额外gen.sh的。这是解决方案:#gen.sh./mybin /dev/stdin /dev/fd/3 3>&1 1>&2// gen.gofunc gen(stdin []byte) ([]byte, error) {    inBuf := bytes.NewBuffer(stdin)    outBuf := bytes.NewBuffer(nil)    cmd := exec.Command("./gen.sh")    cmd.Stdin = inBuf    cmd.Stdout = outBuf    cmd.Stderr = os.Stderr    err := cmd.Run()    if err != nil {        return nil, err    }    return outBuf.Bytes(), nil}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go