Hello I’m new to Go and wish to learn a struct from an XML file in a zipper archive. I’m having hassle becoming the items collectively – I can get one thing to work however it appears like there must be a extra simple manner.
To start out I consider I want to make use of zip.OpenReader
to get a zip.ReadCloser
. On the finish I have to have some []byte
to go to xml.Unmarshall
.
Within the center I had two ideas:
- Use
zip.ReadCloser.Open
to open a file – however this returns anfs.File
which doesn’t have a simple strategy to learn its total contents as bytes, that I can see. Additionally this appears to want to repeat the bytes which isn’t wanted, as a result of the zip file is already decompressed in reminiscence. - Iterate by means of the
zip.ReadCloser.File
s trying to find the file title I need. Then thezip.Reader.File
does have a simple strategy to learn it, callingOpen
after whichio.ReadAll
. But it surely appears unlucky I have to do a linear iteration of the information myself.
So I’m simply in search of feedback actually, is there a better manner to do that that I haven’t noticed?
Thanks prematurely.
Right here is a few code, I do know I’ve skipped all of the error dealing with and defer
shut stuff for simplicity.
func one() {
// var r *zip.ReadCloser
r, _ := zip.OpenReader("na.zip")
// var f fs.File
f, _ := r.Open("customized.xml")
// var bytes []byte
// ** Any strategy to keep away from implementing this perform myself?
bytes, _ := readfsfile(f)
// var customized Customized
customized := Customized{}
xml.Unmarshal(bytes, &customized)
fmt.Println(customized)
}
func two() {
// var r *zip.ReadCloser
r, _ := zip.OpenReader("na.zip")
// var file zip.Reader.File
// ** Any strategy to keep away from this iteration?
for _, file := vary r.File {
if file.Title == "customized.xml" {
// var reader io.ReadCloser
reader, _ := file.Open()
// var bytes []byte
bytes, _ := io.ReadAll(reader)
// var customized Customized
customized := Customized{}
xml.Unmarshal(bytes, &customized)
fmt.Println(customized)
}
}
}
Hey there. So far as I can see with the primary possibility, Open
returns ReadCloser as nicely, so you should utilize it’s Learn
technique identical as within the second possibility.
f, _ := r.Open("file in archive")
defer f.Shut()
knowledge, _ := io.ReadAll(f)
Imho I want the second possibility, for the reason that first one limits you to figuring out file path prematurely.
Nice, thanks. I actually was lacking one thing!
Is it right to say that fs.File
is a Reader
(and therefore will be handed to io.ReadAll
) simply because it has the Learn(p []byte) (n int, err error)
technique? I learn one thing about this however didn’t fairly grasp it clearly. I used to be anticipating the docs to say “implements Reader” or one thing.
Additionally in my case I do know the file path throughout the zip prematurely, it’s all the time the identical, in order that’s OK.
Yeah, typically docs don’t specify this immediately. However you’ll be able to test the supply code. If it implements strategies for the interface. Or, like on this case, returns interface with embedded strategies
Only a fast notice if you wish to attempt to simplify issues a bit. Take a have a look at what xml.Unmarshal
is doing:
func Unmarshal(knowledge []byte, v any) error {
return NewDecoder(bytes.NewReader(knowledge)).Decode(v)
}
And in case you monitor down the perform signature of xml.NewDecoder you will notice it takes an io.Reader
:
func NewDecoder(r io.Reader) *Decoder
Your io.ReadCloser
is a reader. So you’ll be able to simply go it to NewDecoder
and never learn all of the bytes into reminiscence first:
if file.Title == "customized.xml" {
// var reader io.ReadCloser
reader, _ := file.Open()
// var customized Customized
customized := Customized{}
err := xml.NewDecoder(reader).Decode(&customized)
// Deal with err
fmt.Println(customized)
}
2 Likes