Te sugerimos que revises esta solución en un ambiente controlado antes de enviarlo a producción, un saludo.
Solución:
Ligera reelaboración de la solución del OP para crear el directorio contenedor dest
si no existe, y envolver la extracción/escritura del archivo en un cierre para eliminar el apilamiento de defer .Close()
llamadas según el comentario de @Nick Craig-Wood:
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)
// Check for ZipSlip (Directory traversal)
if !strings.HasPrefix(path, filepath.Clean(dest) + string(os.PathSeparator))
return fmt.Errorf("illegal file path: %s", path)
if f.FileInfo().IsDir()
os.MkdirAll(path, f.Mode())
else os.O_CREATE
return nil
for _, f := range r.File
err := extractAndWriteFile(f)
if err != nil
return err
return nil
Nota: Actualizado para incluir también el manejo de errores Close() (si estamos buscando las mejores prácticas, también podemos seguirlas TODAS).
Estoy usando archive/zip
paquete para leer archivos .zip y copiarlos en el disco local. A continuación se muestra el código fuente para descomprimir archivos .zip para mis propias necesidades.
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
return nil
Preferiría usar 7zip con Go, que te daría algo como esto.
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)
Mejor código de ejemplo
Sin embargo, si no es posible usar 7zip, intente esto. Aplazar una recuperación para atrapar los pánicos. (Ejemplo)
func checkError(e error)
if e != nil
panic(e)
func cloneZipItem(f *zip.File, dest string)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)
Eres capaz de añadir valor a nuestra información asistiendo con tu veteranía en las críticas.