问题
I am working on a program that compresses xml files to gzip using golang.
but the program failed to generate files, however it does generate the output when I try to convert .txt file to gzip . Here is my program:-
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io"
"log"
"os"
)
type Notes struct {
To string `xml:"to"`
From string `xml:"from"`
Heading string `xml:"heading"`
Body string `xml:"body"`
}
func main() {
var buf bytes.Buffer
zw := gzip.NewWriter(&buf)
// Setting the Header fields is optional.
zw.Name = "new.xml"
_, err := zw.Write([]byte("Compressing"))
if err != nil {
log.Fatal(err)
}
if err := zw.Close(); err != nil {
log.Fatal(err)
}
zr, err := gzip.NewReader(&buf)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Name: %s", zr.Name)
if _, err := io.Copy(os.Stdout, zr); err != nil {
log.Fatal(err)
}
if err := zr.Close(); err != nil {
log.Fatal(err)
}
}
What should I do for generating the .gz file I desire.
回答1:
Right now, zw.Write()
calls will write the (compressed) data into buff
. Since, instead, you want to write it to a file, you should create something that does just that.
The easiest way is to use os.Create()
. This function returns a *os.File
, which implements io.Writer
.
The resulting code would be something like this:
package main
import (
"compress/gzip"
"log"
"os"
)
func main() {
// This creates a file and returns an implementation of io.Writer
fileWriter, err := os.Create("./file.gz")
if err != nil {
log.Println(err)
return
}
defer fileWriter.Close()
// Use the io.Writer to create the gzip.Writer.
zw := gzip.NewWriter(fileWriter)
defer zw.Close()
// Setting the Header fields is optional.
zw.Name = "new.xml"
// When gzip.Writer.Write is called, it will pass on the data to the Write func of the io.Writer we passed on line 17.
// If there is an error writing to the actual file, it will be returned.
_, err = zw.Write([]byte("Compressing"))
if err != nil {
log.Println(err)
return
}
}
This way of composing writers makes it very easy to change how things work without changing to much code. You can take this composition a step further, because *xml.Encoder
is also an implementation of io.Writer
that takes another io.Writer
as parameter, just like *gzip.Writer
does. So to actually generate and write XML to a file and gzip it along the way, you would just do the following:
package main
import (
"compress/gzip"
"encoding/xml"
"log"
"os"
)
type Notes struct {
To string `xml:"to"`
From string `xml:"from"`
Heading string `xml:"heading"`
Body string `xml:"body"`
}
func main() {
// This creates a file and returns *os.File, an implementation of io.Writer
fileWriter, err := os.Create("./notes.gz")
if err != nil {
log.Println(err)
return
}
defer fileWriter.Close()
// Use the io.Writer to create the gzip.Writer.
zw := gzip.NewWriter(fileWriter)
defer zw.Close()
// Setting the Header fields is optional.
zw.Name = "notes.xml"
notes := []Notes{
{
To: "Alice",
From: "Bob",
Heading: "Hi",
Body: "Hey Alice, how are you?",
},
{
To: "Bob",
From: "Alice",
Heading: "Re: Hi",
Body: "Hi Bob! I'm fine, thnx.",
},
}
// Create the xml.Encoder, using the gzip.Writer (which implements io.Writer).
xmlWriter := xml.NewEncoder(zw)
// So now, we have an xml.Encoder which writes to a gzip.Writer which writes to io.File.
// This call to Encode() will generate the XML, pass that to gzip.Writer.Write, which passes it to os.File.Write.
err = xmlWriter.Encode(notes)
if err != nil {
log.Println(err)
return
}
}
This way of composing writers (as well as readers) is very powerful. You can find it in a lot of places, making is very easy to "layer" writers.
来源:https://stackoverflow.com/questions/59785830/golang-problem-in-converting-xml-to-gzip