This project is a highly optimized and advanced drop-in replacement for the Go standard library archive/zip.
It combines the stability of the standard library with the best open-source ZIP processing features available in the Go ecosystem into a single, powerful package.
-
Drop-in Compatibility: 100% compatible with the
archive/zipAPI. You can safely replace yourarchive/zipimports withgithub.com/unxed/zip. -
High Performance: Uses the blazing-fast
klauspost/compresslibrary forDEFLATEand adds nativeZstandard (ZSTD)support. Both reading and writing are heavily optimized with buffer pooling. -
Parallel Archiving & Extraction: A concurrent archiver and extractor (adapted from
saracen/fastzip) processes multiple files in parallel, significantly speeding up operations on multi-core systems. -
Advanced Encryption:
- WinZip AES (AE-2): Full support for reading and writing AES-encrypted archives (128, 192, and 256-bit).
- Central Directory Encryption (CDE): Encrypt the archive's metadata (filenames, sizes, etc.), making the list of files completely invisible without the correct password.
-
Broad Compression Support:
- Built-in Deflate64 (Method 9) decoder, used by Windows for large files.
- Support for BZIP2, LZMA, and PPMd decompression.
-
In-Place Updates (Updater): Modify existing ZIP files by appending or overwriting entries without performing a full re-compression of the entire archive.
-
Cross-Platform Metadata:
- Unix: Automatic preservation and restoration of UID/GID and extended timestamps.
- Windows: Support for reading and writing NTFS Security Descriptors (ACLs; WIP).
-
Legacy Codepage Auto-Detection: Includes the advanced heuristic algorithm from
7-zipandfar2lto automatically fix "mojibake" (garbled text) in filenames from legacy archives created on different operating systems. -
Multi-Volume Support: Transparently read split ZIP archives (e.g.,
archive.z01,archive.z02, ...,archive.zip).
Simply replace the import path. All existing code for archive/zip will work.
import "github.com/unxed/zip"
// Use exactly like the standard library
r, err := zip.OpenReader("archive.zip")
if err != nil {
log.Fatal(err)
}
defer r.Close()
// ...The Archiver provides a high-level API for creating archives from a directory structure concurrently.
package main
import (
"context"
"log"
"os"
"path/filepath"
"github.com/unxed/zip"
)
func main() {
sourceDir := "/path/to/source"
w, err := os.Create("archive.zip")
if err != nil {
log.Fatal(err)
}
defer w.Close()
// Create an archiver with 8 concurrent workers
archiver, err := zip.NewArchiver(w, sourceDir, zip.WithArchiverConcurrency(8))
if err != nil {
log.Fatal(err)
}
defer archiver.Close()
// Gather files to be archived
files := make(map[string]os.FileInfo)
filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// Skip the root directory itself
if path != sourceDir {
files[path] = info
}
return nil
})
// Archive all files concurrently
if err := archiver.Archive(context.Background(), files); err != nil {
log.Fatal(err)
}
log.Println("Archiving complete!")
}Modify an archive without rewriting it from scratch using the Updater.
f, err := os.OpenFile("archive.zip", os.O_RDWR, 0)
if err != nil {
log.Fatal(err)
}
defer f.Close()
updater, err := zip.NewUpdater(f)
if err != nil {
log.Fatal(err)
}
// Overwrite an existing file with new content
w, err := updater.Append("config.json", zip.APPEND_MODE_OVERWRITE)
if err != nil {
log.Fatal(err)
}
w.Write([]byte(`{"updated": true}`))
if err := updater.Close(); err != nil {
log.Fatal(err)
}Provide a password in the FileHeader to enable strong WinZip-compatible AES encryption.
w, _ := os.Create("secure.zip")
defer w.Close()
zw := zip.NewWriter(w)
defer zw.Close()
fh := &zip.FileHeader{
Name: "secret.txt",
Method: zip.Deflate,
Password: "super-secret-password",
AESStrength: 3, // 1 for 128-bit, 2 for 192-bit, 3 for 256-bit
}
f, err := zw.CreateHeader(fh)
if err != nil {
log.Fatal(err)
}
f.Write([]byte("this is top secret data"))Encrypt the archive's file list itself, making it impossible to see the contents without a password.
w, _ := os.Create("stealth.zip")
defer w.Close()
zw := zip.NewWriter(w)
defer zw.Close()
// Encrypt the list of files (the central directory)
zw.SetEncryptCentralDirectory(true, "master-password")
// Note: Individual files can still have their own passwords or be unencrypted.
// Here, we encrypt the file with the same password for simplicity.
fh := &zip.FileHeader{
Name: "secret.txt",
Password: "master-password",
}
f, err := zw.CreateHeader(fh)
if err != nil {
log.Fatal(err)
}
f.Write([]byte("top secret data"))The library handles split archives automatically. Just open the final .zip file.
// This will transparently read from archive.z01, archive.z02, etc.
r, err := zip.OpenReader("archive.zip")
if err != nil {
log.Fatal(err)
}
defer r.Close()
// You can now access all files as if it were a single archive
for _, f := range r.File {
fmt.Println("Found file:", f.Name)
}This project is released under the BSD-3-Clause License. See the LICENSE file for details.
This library is inspired by several other open-source zip implementations. Please see CREDITS.md for a detailed list of acknowledgements.