我尝试使用mozjpeg压缩JPEG图像。由于它没有正式的绑定,我想我只是调用它来进行压缩。
我尝试在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?
}
但无法完成它。
另外,第二个问题是,我什么时候关闭命令?如何关闭命令?
答案 0 :(得分: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
读取时执行完成。
答案 1 :(得分:0)
根据Kiril的回答,使用cmd.StdInPipe
将您收到的数据传递给Write
。
然而,就结束而言,我很想实施io.Closer。这将使*Compresser
自动实现io.WriteCloser接口。
我会使用Close()
作为通知,告知不再有数据要发送,并且命令应该终止。从命令返回的任何非零退出代码都可以捕获并作为错误返回。
如果您的输入流速度较慢,我会谨慎使用CombinedOutput()
Write()
。该实用程序可以完成处理输入流并等待更多数据。这将被错误地检测为命令完成,并将导致无效输出。
请记住,在IO操作期间,Write
方法可以被称为不确定的次数。