2013-03-03 91 views
3

我使用imagemagick的convert命令调用内存中的某些数据(来自html表单上传/ web服务器)。这工作正常,但我想在错误的情况下得到错误输出convert。我怎样才能做到这一点?完成处理后读取stderr

这是我的代码:

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. 

,但我不“看”我的小程序中的此错误消息。我如何获取错误信息并将其显示给我的用户?

(而另一子的问题是:你可以给我一个建议,如果这个代码看起来确定是否有任何明显的缺陷?)

+0

您将数据复制出来的方式似乎与Go的想法相矛盾;请参阅[对类似问题的此答案](http://stackoverflow.com/a/9323144/720999)以了解如何以更“高手”的方式执行此操作。 – kostix 2013-03-03 21:11:34

回答

1

stdoutstderr了。例如,

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 
+1

谢谢!也许是一个太大的评论,但无论如何:是否有必要/良好的做法/ ...调用'sdout.Close()'和'stderr.Close()'?或者这是完全可选的,因为他们被其他呼叫关闭了? – topskip 2013-03-03 20:26:10

+0

从'os/exec'软件包'* Cmd.StdoutPipe'和'* Cmd.StdinPipe'方法的文档:“在Wait看到命令退出后,管道将自动关闭。”如果你在'Wait'后面移动'ReadAll'管道,你将不会看到任何东西,因为它关闭了。 – peterSO 2013-03-03 20:37:13

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 
}