Skip to content

Instantly share code, notes, and snippets.

@iamralch
Last active April 16, 2023 03:04
Show Gist options
  • Star 44 You must be signed in to star a gist
  • Fork 17 You must be signed in to fork a gist
  • Save iamralch/424e6784facc0ba907ae to your computer and use it in GitHub Desktop.
Save iamralch/424e6784facc0ba907ae to your computer and use it in GitHub Desktop.
ZIP archives in Golang
import (
"archive/zip"
"io"
"os"
"path/filepath"
"strings"
)
func zipit(source, target string) error {
zipfile, err := os.Create(target)
if err != nil {
return err
}
defer zipfile.Close()
archive := zip.NewWriter(zipfile)
defer archive.Close()
info, err := os.Stat(source)
if err != nil {
return nil
}
var baseDir string
if info.IsDir() {
baseDir = filepath.Base(source)
}
filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
if baseDir != "" {
header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, source))
}
if info.IsDir() {
header.Name += "/"
} else {
header.Method = zip.Deflate
}
writer, err := archive.CreateHeader(header)
if err != nil {
return err
}
if info.IsDir() {
return nil
}
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(writer, file)
return err
})
return err
}
import (
"archive/zip"
"io"
"os"
"path/filepath"
"strings"
)
func unzip(archive, target string) error {
reader, err := zip.OpenReader(archive)
if err != nil {
return err
}
if err := os.MkdirAll(target, 0755); err != nil {
return err
}
for _, file := range reader.File {
path := filepath.Join(target, file.Name)
if file.FileInfo().IsDir() {
os.MkdirAll(path, file.Mode())
continue
}
fileReader, err := file.Open()
if err != nil {
return err
}
defer fileReader.Close()
targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
if err != nil {
return err
}
defer targetFile.Close()
if _, err := io.Copy(targetFile, fileReader); err != nil {
return err
}
}
return nil
}
@yhirose
Copy link

yhirose commented Jan 23, 2016

@Svett, thanks for the very useful code. I have a question on line 21 in compress.go. Is there any reason to return nil instead of err in this case?

@rande
Copy link

rande commented Mar 3, 2016

The extract function will generate too many open file issue as the defer is only called once the function return, here an altered version:

func Unzip(archive, target string) error {
    reader, err := zip.OpenReader(archive)
    if err != nil {
        return err
    }

    if err := os.MkdirAll(target, 0755); err != nil {
        return err
    }

    for _, file := range reader.File {
        path := filepath.Join(target, file.Name)
        if file.FileInfo().IsDir() {
            os.MkdirAll(path, file.Mode())
            continue
        }

        fileReader, err := file.Open()
        if err != nil {

            if fileReader != nil {
                fileReader.Close()
            }

            return err
        }

        targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
        if err != nil {
            fileReader.Close()

            if targetFile != nil {
                targetFile.Close()
            }

            return err
        }

        if _, err := io.Copy(targetFile, fileReader); err != nil {
            fileReader.Close()
            targetFile.Close()

            return err
        }

        fileReader.Close()
        targetFile.Close()
    }

    return nil
}

@dopatraman
Copy link

The zipit function throws an error if the .zip file does not already exist. How do i remedy this?

@anismiles
Copy link

	// Check file
	if _, err := os.Stat(archive); os.IsNotExist(err) {
		return err
	}

@hrieke
Copy link

hrieke commented Oct 19, 2017

License?

@navono
Copy link

navono commented Aug 28, 2020

If have a large files in multiple directory, the filepath.Walk would take a long time to process. Any possible to use goroutine to improve performance?

@royalorc
Copy link

hi all, if I have some sub directories, in the code previous, it just make directory of sub directories, how can i restore those files in sub directories?

@royalorc
Copy link

if r.File[f].FileInfo().IsDir() {
if err := os.MkdirAll(dstpath, os.ModePerm); err != nil {
return nil, err
}
}
in this piece of code, how could i copy those files which are in this directory?

@iamralch
Copy link
Author

You have to walk through the directories until you reach a regular file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment