Как обернуть exec.Command внутри io.Writer
Я пытаюсь сжать изображение в формате JPEG с помощью mozjpeg. Поскольку он не имеет официальной привязки, я просто вызову его CLI для сжатия.
Я пытаюсь смоделировать использование после 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?
}
Но не мог закончить это.
Кроме того, второй вопрос, когда я выключаю команду? Как отключить команду?
2 ответа
Вы должны взглянуть на 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
,
Согласно ответу Кирилла, используйте cmd.StdInPipe
передать данные, которые вы получаете Write
,
Однако, с точки зрения закрытия, я бы соблазнился реализовать io.Closer. Это сделало бы *Compresser
автоматически реализовать интерфейс io.WriteCloser.
я хотел бы использовать Close()
как уведомление о том, что больше нет данных для отправки и что команда должна быть прервана. Любой ненулевой код завершения, возвращенный из команды, которая указывает на сбой, может быть перехвачен и возвращен как ошибка.
Я бы с осторожностью использовал CombinedOutput()
внутри Write()
в случае, если у вас медленный поток ввода. Утилита может завершить обработку входного потока и ожидать дополнительных данных. Это будет неправильно определено как завершение команды и приведет к неверному выводу.
Помните, что Write
метод может вызываться неопределенное количество раз во время операций ввода-вывода.