OP 解决方案的轻微返工以创建包含目录(dest如果它不存在),并将文件提取/写入包装在一个闭包中以消除defer .Close()每个@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.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

}

注意:更新为包括 Close() 错误处理(如果我们正在寻找最佳实践,不妨遵循所有这些)。