2017-07-25 13 views
2

Ich versuche, ein JPEG-Bild in Go mit mozjpeg zu komprimieren. Da es keine offizielle Go-Bindung gibt, denke ich, ich werde einfach seine CLI aufrufen, um die Komprimierung durchzuführen.Wie wickle ich exec.Command innerhalb eines io.Writer

Ich versuche, die Nutzung nach compress/gzip zu modellieren:

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

Nun ist die Frage, wie kann ich die CLI innerhalb Compresser wickeln, damit es diese Verwendung unterstützen kann?

habe ich versucht, so etwas wie dieses:

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? 
} 

Aber könnte es nicht beenden.

Auch eine zweite Frage ist, wann schließe ich den Befehl? Wie man den Befehl herunterfährt?

Antwort

1

Sie sollten sich die Cmd.StdinPipe ansehen. Es gibt ein Beispiel in der Dokumentation, die in Ihrem Fall paßt:

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) 
} 

In diesem Fall CombinedOutput() Ihren Befehl ausführt, und die Ausführung beendet ist, wenn es kein weiteres Bytes von out zu lesen ist.

0

Verwenden Sie gemäß Kirils Antwort die cmd.StdInPipe, um die Daten, die Sie erhalten, an Write weiterzuleiten.

Aber in Bezug auf die Schließung wäre ich versucht zu implementieren io.Closer. Dies würde *Compresser automatisch die io.WriteCloser Schnittstelle implementieren.

Ich würde Close() als die Benachrichtigung verwenden, dass keine Daten mehr gesendet werden sollen und dass der Befehl beendet werden sollte. Jeder Nicht-Null-Exit-Code, der vom fehlgeschlagenen Befehl zurückgegeben wird, könnte abgefangen und als Fehler zurückgegeben werden.

Ich würde vorsichtig sein mit CombinedOutput() innerhalb Write(), falls Sie einen langsamen Eingangsstrom haben. Das Dienstprogramm könnte die Verarbeitung des Eingabestreams abschließen und auf weitere Daten warten. Dies würde fälschlicherweise als Befehlsvervollständigung erkannt und würde zu einer ungültigen Ausgabe führen.

Denken Sie daran, die Write Methode kann eine unbestimmte Anzahl von Zeiten während IO-Operationen aufgerufen werden.

Verwandte Themen