web-dev-qa-db-fra.com

moyen facile de décompresser un fichier avec Golang

existe-t-il un moyen facile de décompresser un fichier avec golang?

en ce moment mon code est:

func Unzip(src, dest string) error {
    r, err := Zip.OpenReader(src)
    if err != nil {
        return err
    }
    defer r.Close()

    for _, f := range r.File {
        rc, err := f.Open()
        if err != nil {
            return err
        }
        defer rc.Close()

        path := filepath.Join(dest, f.Name)
        if f.FileInfo().IsDir() {
            os.MkdirAll(path, f.Mode())
        } else {
            f, err := os.OpenFile(
                path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
            if err != nil {
                return err
            }
            defer f.Close()

            _, err = io.Copy(f, rc)
            if err != nil {
                return err
            }
        }
    }

    return nil
}
27
Akshaydeep Giri

Légère retouche de la solution de l'OP pour créer le répertoire contenant dest s'il n'existe pas, et pour encapsuler l'extraction/écriture du fichier dans une fermeture pour éliminer l'empilement des appels de defer .Close() par - @ Nick Craig-Wood commentaire:

func Unzip(src, dest string) error {
    r, err := Zip.OpenReader(src)
    if err != nil {
        return err
    }
    defer func() {
        if err := r.Close(); err != nil {
            panic(err)
        }
    }()

    os.MkdirAll(dest, 0755)

    // Closure to address file descriptors issue with all the deferred .Close() methods
    extractAndWriteFile := func(f *Zip.File) error {
        rc, err := f.Open()
        if err != nil {
            return err
        }
        defer func() {
            if err := rc.Close(); err != nil {
                panic(err)
            }
        }()

        path := filepath.Join(dest, f.Name)

        if f.FileInfo().IsDir() {
            os.MkdirAll(path, f.Mode())
        } else {
            os.MkdirAll(filepath.Dir(path), f.Mode())
            f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
            if err != nil {
                return err
            }
            defer func() {
                if err := f.Close(); err != nil {
                    panic(err)
                }
            }()

            _, err = io.Copy(f, rc)
            if err != nil {
                return err
            }
        }
        return nil
    }

    for _, f := range r.File {
        err := extractAndWriteFile(f)
        if err != nil {
            return err
        }
    }

    return nil
}

Remarque: Mise à jour pour inclure également la gestion des erreurs Close () (si nous recherchons les meilleures pratiques, elles peuvent toutes les suivre).

41
Astockwell

J'utilise archive/Zip package pour lire les fichiers .zip et copier sur le disque local. Voici le code source pour décompresser les fichiers .zip pour mes propres besoins.

import (
    "archive/Zip"
    "io"
    "log"
    "os"
    "path/filepath"
    "strings"
)

func unzip(src, dest string) error {
    r, err := Zip.OpenReader(src)
    if err != nil {
        return err
    }
    defer r.Close()

    for _, f := range r.File {
        rc, err := f.Open()
        if err != nil {
            return err
        }
        defer rc.Close()

        fpath := filepath.Join(dest, f.Name)
        if f.FileInfo().IsDir() {
            os.MkdirAll(fpath, f.Mode())
        } else {
            var fdir string
            if lastIndex := strings.LastIndex(fpath,string(os.PathSeparator)); lastIndex > -1 {
                fdir = fpath[:lastIndex]
            }

            err = os.MkdirAll(fdir, f.Mode())
            if err != nil {
                log.Fatal(err)
                return err
            }
            f, err := os.OpenFile(
                fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
            if err != nil {
                return err
            }
            defer f.Close()

            _, err = io.Copy(f, rc)
            if err != nil {
                return err
            }
        }
    }
    return nil
}
6
swtdrgn

J'ai fait quelques recherches sur Google et j'ai trouvé à plusieurs reprises des gens disant qu'il n'y avait pas de bibliothèque capable de gérer cela. Peut-être que j'ai raté un référentiel personnalisé dans ma recherche et que quelqu'un d'autre le trouvera pour nous.

Vous pourrez peut-être utiliser io.Copy(src, dest) pour faciliter le processus mais je ne l'ai pas testé du tout.

Par exemple:

os.MkDirAll(dest, r.File.Mode)
d, _ := os.Open(dest)
io.Copy(r.File, d)

Honnêtement, pour moi, votre code est plutôt joli et si je devais faire moi-même une fonction d'extraction (et ce qui précède ne fonctionne pas), je prendrais probablement une page de votre livre.

3
Steven

Je préférerais utiliser 7Zip avec Go, ce qui vous donnerait quelque chose comme ça.

func extractZip() {
    fmt.Println("extracting", Zip_path)
    commandString := fmt.Sprintf(`7za e %s %s`, Zip_path, dest_path)
    commandSlice := strings.Fields(commandString)
    fmt.Println(commandString)
    c := exec.Command(commandSlice[0], commandSlice[1:]...)
    e := c.Run()
    checkError(e)
}

Mieux exemple de code

Cependant, si l'utilisation de 7Zip n'est pas possible, essayez ceci. Reportez une reprise pour attraper les paniques. ( exemple )

func checkError(e error){
  if e != nil {
    panic(e)
  }
}
func cloneZipItem(f *Zip.File, dest string){
    // Create full directory path
    path := filepath.Join(dest, f.Name)
    fmt.Println("Creating", path)
    err := os.MkdirAll(filepath.Dir(path), os.ModeDir|os.ModePerm)
    checkError(err)

    // Clone if item is a file
    rc, err := f.Open()
    checkError(err)
    if !f.FileInfo().IsDir() {
        // Use os.Create() since Zip don't store file permissions.
        fileCopy, err := os.Create(path)
        checkError(err)
        _, err = io.Copy(fileCopy, rc)
        fileCopy.Close()
        checkError(err)
    }
    rc.Close()
}
func Extract(Zip_path, dest string) {
    r, err := Zip.OpenReader(Zip_path)
    checkError(err)
    defer r.Close()
    for _, f := range r.File {
        cloneZipItem(f, dest)
    }
}
3
Larry Battle
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
}
0
blackhat

il y a Zip Slip Vulnerability dans le code de @Astockwell, voir: https://snyk.io/research/Zip-slip-vulnerability

0
woogoo