2013-03-03 96 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 
}