2017-07-25 60 views
2

我試圖用mozjpeg壓縮一個JPEG圖像。由於它沒有正式的綁定,我想我只會調用它的CLI來進行壓縮。如何在一個io.Writer中包裝exec.Command

我嘗試compress/gzip後的使用模式:

c := jpeg.NewCompresser(destFile) 
_, err := io.Copy(c, srcFile) 

現在的問題是,我怎麼換行CLI內Compresser所以它可以支持這種用法?

我想是這樣的:

type Compresser struct { 
    cmd exec.Command 
} 

func NewCompressor(w io.Writer) *Compresser { 
    cmd := exec.Command("jpegtran", "-copy", "none") 
    cmd.Stdout = w 
    c := &Compresser{cmd} 
    return c 
} 

func (c *Compresser) Write(p []byte) (n int, err error) { 
    if c.cmd.Process == nil { 
     err = c.cmd.Start() 
     if err != nil { 
      return 
     } 
    } 
    // How do I write p into c.cmd.Stdin? 
} 

,但不能完成它。

另外,第二個問題是,我何時關閉命令?如何關閉命令?

回答

1

你應該看看Cmd.StdinPipe。還有就是文檔,適合你的情況爲例:

package main 

import (
    "fmt" 
    "io" 
    "log" 
    "os/exec" 
) 

func main() { 
    cmd := exec.Command("cat") 
    stdin, err := cmd.StdinPipe() 
    if err != nil { 
     log.Fatal(err) 
    } 

    go func() { 
     defer stdin.Close() 
     io.WriteString(stdin, "values written to stdin are passed to cmd's standard input") 
    }() 

    out, err := cmd.CombinedOutput() 
    if err != nil { 
     log.Fatal(err) 
    } 

    fmt.Printf("%s\n", out) 
} 

在這種情況下,CombinedOutput()執行你的命令,執行結束了,當沒有更多的字節從out閱讀。

0

按照Kiril的回答,使用cmd.StdInPipe將收到的數據傳遞給Write

但是,就結案而言,我會試圖實施io.Closer。這將使*Compresser自動實現io.WriteCloser接口。

我會使用Close()作爲沒有更多數據要發送並且該命令應該終止的通知。從指示失敗的命令返回的任何非零退出代碼都可能被捕獲並作爲錯誤返回。

如果輸入流緩慢,我會在Write()以內使用CombinedOutput()。該實用程序可以完成處理輸入流並等待更多數據。這將被錯誤地檢測爲命令完成並導致無效輸出。

請記住,在IO操作過程中,Write方法可以被稱爲不確定次數。