is there a easy way to unzip file with golang ?
right now my code is:
func Unzip(src, dest string) error {
r, err := zip.OpenReader(src)
if err !
package main
import (
"os"
"io"
"io/ioutil"
"fmt"
"strings"
"archive/zip"
"path/filepath"
)
func main() {
if err := foo("test.zip"); err != nil {
fmt.Println(err)
}
}
func foo(yourZipFile string) error {
tmpDir, err := ioutil.TempDir("/tmp", "yourPrefix-")
if err != nil {
return err
}
defer os.RemoveAll(tmpDir)
if filenames, err := Unzip(yourZipFile, tmpDir); err != nil {
return err
} else {
for f := range filenames {
fmt.Println(filenames[f])
}
}
return nil
}
func Unzip(src string, dst string) ([]string, error) {
var filenames []string
r, err := zip.OpenReader(src)
if err != nil {
return nil, err
}
defer r.Close()
for f := range r.File {
dstpath := filepath.Join(dst, r.File[f].Name)
if !strings.HasPrefix(dstpath, filepath.Clean(dst) + string(os.PathSeparator)) {
return nil, fmt.Errorf("%s: illegal file path", src)
}
if r.File[f].FileInfo().IsDir() {
if err := os.MkdirAll(dstpath, os.ModePerm); err != nil {
return nil, err
}
} else {
if rc, err := r.File[f].Open(); err != nil {
return nil, err
} else {
defer rc.Close()
if of, err := os.OpenFile(dstpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, r.File[f].Mode()); err != nil {
return nil, err
} else {
defer of.Close()
if _, err = io.Copy(of, rc); err != nil {
return nil, err
} else {
of.Close()
rc.Close()
filenames = append(filenames, dstpath)
}
}
}
}
}
if len(filenames) == 0 {
return nil, fmt.Errorf("zip file is empty")
}
return filenames, nil
}
Every single answer on this page is wrong, as they all assume that the Zip archive will emit directory entries. Zip archives are not required to emit directory entries, and so given an archive such as that, a naive program will crash upon encountering the first non-root file, as no directories will ever be created, and the file creation will fail as the directory has not been created yet. Here is a different approach:
package main
import (
"archive/zip"
"os"
"path"
)
func Unzip(source string) error {
zip_o, e := zip.OpenReader(source)
if e != nil {
return e
}
for _, file_o := range zip_o.File {
if file_o.Mode().IsDir() {
continue
}
dir_s := path.Dir(file_o.Name)
os.MkdirAll(dir_s, os.ModeDir)
open_o, e := file_o.Open()
if e != nil {
return e
}
create_o, e := os.Create(file_o.Name)
if e != nil {
return e
}
create_o.ReadFrom(open_o)
}
return nil
}
Example use:
package main
import "log"
func main() {
e := Unzip("Microsoft.VisualCpp.Tools.HostX64.TargetX64.vsix")
if e != nil {
log.Fatal(e)
}
}