3

convert我用内存中的一些数据(来自 html 表单上传/网络服务器)调用 imagemagick 的命令。这工作正常,但我想在出现错误时获得错误输出convert。我怎样才能做到这一点?

这是我的代码:

package main

import (
    "bytes"
    "io"
    "io/ioutil"
    "log"
    "os/exec"
    "path/filepath"
)

func runImagemagick(data []byte, destfilename string) error {
    data_buf := bytes.NewBuffer(data)

    cmd := exec.Command("convert", "-", destfilename)
    stdin, err := cmd.StdinPipe()
    if err != nil {
        return err
    }

    err = cmd.Start()
    if err != nil {
        return err
    }
    _, err = io.Copy(stdin, data_buf)
    if err != nil {
        return err
    }
    stdin.Close()
    err = cmd.Wait()
    if err != nil {
        return err
    }
    return nil
}

func main() {
    data, err := ioutil.ReadFile("source.gif")
    if err != nil {
        log.Fatal(err)
    }
    err = runImagemagick(data, filepath.Join("/tmp", "abc", "dest.png"))
    if err != nil {
        log.Fatal(err)
    }
}

现在人为的问题是目录/tmp/abc/不存在。通常convert会给我这个结果:

$ convert - /tmp/abc/foo.png < source.gif 
convert: unable to open image `/tmp/abc/foo.png': No such file or directory @ error/blob.c/OpenBlob/2617.
convert: WriteBlob Failed `/tmp/abc/foo.png' @ error/png.c/MagickPNGErrorHandler/1755.

但我没有在我的小程序中“看到”这个错误消息。如何获取错误消息并将其显示给我的用户?

(另一个子问题是:如果这段代码看起来不错,你能给我一个建议吗?它有什么明显的缺陷吗?)

4

2 回答 2

1

管子stdout也是stderr。例如,

package main

import (
    "bytes"
    "io"
    "io/ioutil"
    "log"
    "os/exec"
    "path/filepath"
)

func runImagemagick(data []byte, destfilename string) error {
    cmd := exec.Command("convert", "-", destfilename)
    stdin, err := cmd.StdinPipe()
    if err != nil {
        return err
    }
    stdout, err := cmd.StdoutPipe()
    if err != nil {
        return err
    }
    stderr, err := cmd.StderrPipe()
    if err != nil {
        return err
    }
    err = cmd.Start()
    if err != nil {
        return err
    }
    _, err = io.Copy(stdin, bytes.NewBuffer(data))
    if err != nil {
        return err
    }
    stdin.Close()
    outData, err := ioutil.ReadAll(stdout)
    if err != nil {
        return err
    }
    if len(outData) > 0 {
        log.Print(string(outData))
    }
    errData, err := ioutil.ReadAll(stderr)
    if err != nil {
        return err
    }
    if len(errData) > 0 {
        log.Print(string(errData))
    }
    err = cmd.Wait()
    if err != nil {
        return err
    }
    return nil
}

func main() {
    data, err := ioutil.ReadFile("source.gif")
    if err != nil {
        log.Fatal(err)
    }
    err = runImagemagick(data, filepath.Join("/tmp", "abc", "dest.png"))
    if err != nil {
        log.Fatal(err)
    }
}

输出:

2013/03/03 15:02:20 convert.im6: unable to open image `/tmp/abc/dest-0.png': No such file or directory @ error/blob.c/OpenBlob/2638.
convert.im6: WriteBlob Failed `/tmp/abc/dest-0.png' @ error/png.c/MagickPNGErrorHandler/1728.
2013/03/03 15:02:20 exit status 1
exit status 1
于 2013-03-03T20:04:35.203 回答
1

不需要使用管道,因为bytes.Buffer实现了io.Writer接口,因此可以很好地使用它来收集程序的输出:

func runImagemagick(data []byte, destfilename string) error {     
    cmd := exec.Command("convert", "-", destfilename)

    var stdout, stderr bytes.Buffer
    cmd.Stdout = &stdout
    cmd.Stderr = &stderr

    err := cmd.Run()
    if err != nil {
        if ee, ok := err.(*exec.ExitError); ok {
            return &imagemagickError{ee, stdout.Bytes(), stderr.Bytes()}
        } else {
            return err
        }
    }

    if stderr.Len() > 0 {
        return errors.New(fmt.Sprintf("imagemagick wrote to stderr: %s", stderr.Bytes()))
    }

    if stdout.Len() > 0 {
        log.Print(stdout.Bytes())
    }
    return nil
 }
于 2013-03-03T21:08:26.643 回答