gozip

package module
v1.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 10, 2026 License: BSD-3-Clause Imports: 32 Imported by: 0

README

GoZip

Go Reference Go Report Card

A high-performance, concurrency-safe replacement for the standard archive/zip.

GoZip is designed for high-load applications where speed, security, and interface flexibility are critical. It treats file systems, memory buffers, and network streams as first-class citizens, allowing you to manipulate archives without managing temporary files or complex buffers.

⚡ At a Glance

Why switch from the standard library?

Feature archive/zip (StdLib) GoZip
Concurrency Single-threaded Parallel (Multi-core)
Performance Baseline ~4x Faster (See Benchmarks)
Security Vulnerable to Zip Slip Native Protection
I/O Source File / ReaderAt Polymorphic (File, URL, Buffer)
Encryption Legacy ZipCrypto (Read-only) AES-256 & ZipCrypto (R/W)
Editing Append only Modify / Rename / Remove
Control No cancellation Context-aware

🚀 Key Capabilities

  • Cloud-Native I/O: Stream archives directly from HTTP/S3 to the client without touching the disk.
  • No External Dependencies The core library relies strictly on the Go standard library.
  • Zero-Overhead Abstraction: Unified API for files, bytes, and streams using Source and Sink interfaces.
  • The Archiver Pattern: No global state side-effects. Configure passwords and codecs once, reuse everywhere.
  • Resilience: "Best Effort" strategy collects all errors (errors.Join) instead of failing on the first file.
  • Legacy Support: Automatically handles Zip64, NTFS timestamps, Unix permissions, and CP866 (DOS) encodings.

📊 Performance Benchmarks

GoZip utilizes a fixed worker pool, memory pooling (sync.Pool), and a Zero-Allocation pipeline. It achieves massive speedups while maintaining allocation parity with the standard library.

Environment: Intel Core i5-12400F (6 cores, 12 threads)

Compression Speed
Scenario Standard Lib GoZip (Sequential) GoZip (Parallel) Speedup
1,000 Small Files 14.3 ms 15.0 ms 3.9 ms 3.7x faster
10 Medium Files (100MB) 179.8 ms 177.9 ms 42.2 ms 4.3x faster
Memory Efficiency
Metric Standard Lib GoZip (Sequential) GoZip (Parallel) Impact
Allocations 12,016 op 12,078 op 12,568 op < 5% overhead
Memory Usage 0.48 MB/op 1.71 MB/op 13.8 MB/op Bounded by worker count

Note: GoZip trades a fixed amount of buffer memory (per worker) to saturate CPU cores, ensuring the GC remains idle even under heavy load.


📦 Installation

go get github.com/lemon4ksan/gozip@latest

📖 Usage Guide

1. The One-Liners (Simple)

For 90% of use cases, use the static helpers with safe defaults (Deflate compression, auto-detection).

package main

import "github.com/lemon4ksan/gozip"

func main() {
    // Archive a directory to a file
    gozip.ArchiveDir("data/images", gozip.ToFilePath("backup.zip"))

    // Extract specific files
    gozip.Unzip(
        gozip.FromFilePath("backup.zip"),
        "restored/",
        gozip.WithFromDir("images"), // Extract only this folder
    )

    // Read single file content directly into memory
    data, _ := gozip.ReadFile(gozip.FromFilePath("logs.zip"), "error.log")
}
2. The Archiver (Configured)

Use NewArchiver when you need specific settings (encryption, compression levels) isolated from the rest of your app.

func main() {
    // Create a reusable configuration
    archiver := gozip.NewArchiver(
        gozip.WithArchivePassword("secure-password-123"),
        gozip.WithCompression(gozip.ZStandard, zstd.SpeedBestCompression),
        // gozip.WithWorkers(4), // Optional: Limit concurrency
    )

    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    // Use it for multiple operations
    err := archiver.UnzipWithContext(ctx, gozip.FromFilePath("encrypted.zip"), "out/")
}
3. Modifying Archives (Edit Mode)

GoZip allows surgical modifications to existing archives (Edit-in-place logic).

func main() {
    archive := gozip.NewZip()
    
    // Load existing metadata (lightweight, doesn't read contents yet)
    src, _ := os.Open("app.zip")
    archive.LoadFromFile(src)
    src.Close()

    // Modify structure
    archive.Remove("logs/")
    archive.Rename("config.dev.json", "config.json")
    
    // Add new file dynamically (Lazy execution)
    archive.AddLazy("db.dump", func() (io.ReadCloser, error) {
        return exec.Command("pg_dump", "db").StdoutPipe()
    })

    // Write the new version
    out, _ := os.Create("app_v2.zip")
    archive.WriteTo(out)
}
4. Advanced: Polymorphic I/O

You can perform operations on any Source (File, URL, Buffer) using the unified API.

// Calculate SHA256 of a remote ZIP without storing it on disk
func HashRemoteZip(url string) string {
    h := sha256.New()
    
    // gozip handles the HTTP range requests or buffering automatically
    gozip.UseSource(gozip.FromURL(url, http.DefaultClient), 
        func(r io.Reader, _ io.ReaderAt, _ int64) error {
            _, err := io.Copy(h, r)
            return err
        },
    )
    return hex.EncodeToString(h.Sum(nil))
}

⚙️ Configuration & Options

Functional Options

Configure operations per-file or per-archive:

  • WithName("new.txt"): Rename file inside the archive.
  • WithCompression(method, level): Override compression.
  • WithEncryption(method, password): Set AES-256 or ZipCrypto.
  • WithWorkers(n): Set number of parallel workers.
  • WithProgress(callback): track progress of operations.
Filters

Selectively process files:

  • WithOnly([]*File): Whitelist specific files.
  • WithFromDir("folder"): Restrict operation to a specific directory.
  • WithExcludeDir("folder"): Blacklist a directory.
Sorting Strategies
  • SortDefault: Preserves insertion order.
  • SortAlphabetical: Deterministic order (A-Z).
  • SortSizeDescending: Ensures heavy files don't block the output queue in parallel mode.
  • SortZIP64Optimized: Buckets files by size to optimize Zip64 header overhead.

⚠️ Error Handling

GoZip uses structured error handling.

  • Bulk operations return errors.Join.
  • Specific errors are wrapped in *FileError for introspection.
Error Description
ErrFormat Not a valid ZIP archive (invalid signatures).
ErrPasswordMismatch Incorrect password or missing password.
ErrChecksum CRC-32 integrity check failed.
ErrInsecurePath Zip Slip detected: file path attempts to escape destination.
ErrDuplicateEntry A file with this name already exists in the archive.
ErrAlgorithm Compression method not supported (e.g., LZMA without plugin).
ErrFileNotFound Requested entry is missing. Wraps fs.ErrNotExist.
ErrFilenameTooLong Filename exceeds the ZIP limit of 65,535 bytes.
ErrResourceLimit Extraction exceeded defined limits.
ErrNotImplemented Code path is not implemented.

License

This code is licensed under the same conditions as the original Go code. See LICENSE file.

Documentation

Overview

Package gozip provides a high-performance, concurrency-safe, and feature-rich implementation of the ZIP archive format.

It is designed as a robust alternative to the standard library's archive/zip, specifically built for high-load applications, security-conscious environments, and developer experience.

Key Features

1. Architecture: The library uses the Archiver to encapsulate configuration (passwords, codecs). No global state or side effects.

2. Usability: Includes high-level helpers (ArchiveDir, Unzip, Diff) for common tasks, reducing boilerplate code to the minimum.

3. Concurrency: Supports parallel compression and extraction, utilizing all available CPU cores for maximum throughput using WithWorkers.

4. Security: Native support for WinZip AES-256 encryption and built-in "Zip Slip" protection during extraction to prevent directory traversal attacks.

5. Abstraction: Uses Source and Sink interfaces to transparently handle files on disk, in-memory buffers, or network streams.

6. Context Awareness: All long-running operations support context.Context for cancellation and timeout management.

7. Compatibility: Handles Zip64 (files > 4GB), NTFS timestamps, Unix permissions, and legacy DOS encodings (CP437, CP866) automatically.

Quick Start

The simplest way to use the library is via global helper functions that use default settings (Deflate compression):

// Archive a directory
err := gozip.ArchiveDir("data/", gozip.ToFilePath("backup.zip"))

// Extract an archive
err := gozip.Unzip(gozip.FromFilePath("backup.zip"), "restored/")

// Read a single file contents without extraction
data, err := gozip.ReadFile(gozip.FromFilePath("config.zip"), "settings.json")

Advanced Usage (The Archiver)

For custom configuration (passwords, specific compression algorithms), create an Archiver instance. This allows you to isolate settings per operation.

// Configure an environment
archiver := gozip.NewArchiver(
    gozip.WithArchivePassword("secure-password"),
    // gozip.WithCompressor(gozip.Zstd, zstd.NewFactory()), // If using custom codecs
)

// Use the configured instance
err := archiver.Unzip(gozip.FromFilePath("encrypted.zip"), "output/")

Source & Sink

The library abstracts IO operations. You can work with physical files, byte slices, or streams seamlessly:

// Unzip from memory (e.g., uploaded file)
src := gozip.FromReader(bytes.NewReader(data), int64(len(data)))
gozip.Unzip(src, "uploads/")

// Archive directly to an HTTP response
dest := gozip.ToWriter(httpResponseWriter)
gozip.ArchiveDir("report/", dest)

Error handling

FileError is used for errors related to File instance and operations, allowing users to access file metadata (name, size) for logging/retry logic. Plain wrapped errors are used for global archive issues. Example:

_, err := archive.AddFile("data/report.pdf")
if err != nil {
    var fileErr *gozip.FileError
    if errors.As(err, &fileErr) {
        fmt.Printf("Operation: %s\n", fileErr.Op)   // e.g., "add", "compress", "extract"
        fmt.Printf("File:      %s\n", fileErr.File.Name())
        fmt.Printf("Cause:     %v\n", fileErr.Err)  // Underlying error (e.g., [ErrPasswordMismatch])
    }
}

Manual Control (Low-Level)

Creating an archive:

archive := gozip.NewZip()
archive.AddFile("file.txt")
archive.AddDir("images/", WithCompression(gozip.Deflate, gozip.DeflateMaximum))

f, _ := os.Create("output.zip")
archive.WriteTo(f)

Modifying an existing archive:

archive := gozip.NewZip()
src, _ := os.Open("old.zip")
archive.LoadFromFile(src)

// 1. Remove obsolete files
archive.Remove("logs/obsolete.log")

// 2. Modify a file
files, _ := archive.Remove("data/config.json")
archive.AddLazy(files[0].Name(), func() (io.ReadCloser, error) {
	pr, pw := io.Pipe()
	go func() {
		defer pw.Close()
		rc, err := file.Open()
		if err != nil {
			pw.CloseWithError(err)
			return
		}
		defer rc.Close()
		processor.Transform(rc, pw)
	}()
	return pr, nil
})

// 3. Rename entries
archive.Rename("dir/old", "new") // -> dir/new

// Save changes to a new writer
dest, _ := os.Create("new.zip")
archive.WriteTo(dest, gozip.WithWorkers(runtime.NumCPU()))

// Close source after the work is done
src.Close()

Index

Constants

View Source
const (
	DeflateNormal    = flate.DefaultCompression // -1
	DeflateMaximum   = flate.BestCompression    // 9
	DeflateFast      = 3
	DeflateSuperFast = flate.BestSpeed     // 1 (Same as Fast in stdlib)
	DeflateStore     = flate.NoCompression // 0
)

Compression levels for DEFLATE algorithm.

View Source
const (
	// LatestZipVersion represents the maximum ZIP specification version supported
	// by this implementation. Version 63 corresponds to ZIP 6.3 specification.
	LatestZipVersion uint16 = 63

	// StandardSizeLimit determines the maximum file size standard zip can store.
	// If this value is exceeded, the Zip64 format must be used.
	StandardSizeLimit = internal.MaxUint32

	// StandardEntriesLimit determines the maximum number of files standard zip can store.
	// If this value is exceeded, the Zip64 EOCD and locator must be used.
	StandardEntriesLimit = internal.MaxUint16

	// MaxStringLength determines the maximum length for filename and comment.
	MaxStringLength = internal.MaxUint16

	// ExtraFieldLimit determines the maximum extra field length the zip can hold.
	ExtraFieldLimit = internal.MaxUint16

	// Zip64ExtraFieldTag identifies the extra field that contains 64-bit size
	// and offset information for files exceeding 4GB limits.
	Zip64ExtraFieldTag = internal.Zip64ExtraFieldTag

	// NTFSFieldTag identifies the extra field that stores high-precision
	// NTFS file timestamps with 100-nanosecond resolution.
	NTFSFieldTag = internal.NTFSFieldTag

	// AESEncryptionTag identifies the extra field for WinZip AES encryption metadata,
	// including encryption strength and actual compression method.
	AESEncryptionTag = internal.AESEncryptionTag
)

Constants defining ZIP format structure and special tag values

View Source
const SizeUnknown int64 = -1

SizeUnknown is a sentinel value used when the data size cannot be determined before writing (e.g., streaming from io.Reader).

Variables

View Source
var (
	// ErrFormat is returned when the input is not a valid ZIP archive.
	ErrFormat = errors.New("zip: not a valid zip file")

	// ErrNotImplemented is returned if this code path is not implemented.
	ErrNotImplemented = errors.New("zip: not implemented")
)

Global errors

View Source
var (
	// ErrFileEntry is returned when an invalid argument is passed to File creation.
	ErrFileEntry = errors.New("not a valid file entry")

	// ErrAlgorithm is returned when a compression algorithm is not supported.
	ErrAlgorithm = errors.New("unsupported compression algorithm")

	// ErrPasswordMismatch is returned when the provided password does not match
	// or when a password is required but not provided.
	ErrPasswordMismatch = errors.New("invalid password")

	// ErrChecksum is returned when reading a file checksum does not match.
	ErrChecksum = errors.New("checksum error")

	// ErrSizeMismatch is returned when the uncompressed size does not match the header.
	ErrSizeMismatch = errors.New("uncompressed size mismatch")

	// ErrFileNotFound is returned when the requested file is not found in the archive.
	// It wraps fs.ErrNotExist so it can be checked with os.IsNotExist.
	ErrFileNotFound = fmt.Errorf("file not found: %w", fs.ErrNotExist)

	// ErrInsecurePath is returned when a file path is invalid or attempts directory traversal (Zip Slip).
	ErrInsecurePath = errors.New("insecure file path")

	// ErrDuplicateEntry is returned when attempting to add a file with a name that already exists.
	ErrDuplicateEntry = errors.New("duplicate file name")

	// ErrFilenameTooLong is returned when a filename exceeds 65535 bytes.
	ErrFilenameTooLong = errors.New("filename too long")

	// ErrCommentTooLong is returned when a file comment exceeds 65535 bytes.
	ErrCommentTooLong = errors.New("comment too long")

	// ErrExtraFieldTooLong is returned when the total size of extra fields exceeds 65535 bytes.
	ErrExtraFieldTooLong = errors.New("extra field too long")

	// ErrResourceLimit is returned when extraction uses too much resources.
	ErrResourceLimit = errors.New("resource limit exceeded")
)

File errors

View Source
var DefaultArchiver = NewArchiver(
	WithZipConfig(ZipConfig{
		CompressionMethod: Deflate,
		CompressionLevel:  DeflateNormal,
		FileSortStrategy:  SortZIP64Optimized,
	}),
)
View Source
var DefaultStoreExtensions = map[string]struct{}{
	"7z": {}, "aar": {}, "ace": {}, "apk": {}, "arc": {}, "arj": {},
	"br": {}, "bz2": {}, "cab": {}, "deb": {}, "dmg": {}, "epub": {},
	"gz": {}, "jar": {}, "lz4": {}, "lzma": {}, "lzo": {}, "rar": {},
	"rpm": {}, "tar": {}, "tgz": {}, "war": {}, "xz": {}, "zip": {},
	"zst": {},

	"mp4": {}, "mkv": {}, "avi": {}, "mov": {}, "webm": {},
	"jpg": {}, "jpeg": {}, "png": {}, "gif": {}, "webp": {},
	"mp3": {}, "ogg": {}, "flac": {},

	"pdf": {}, "docx": {}, "xlsx": {}, "pptx": {},
}

DefaultStoreExtensions is an extended list of formats that are already compressed and do not require reprocessing.

Functions

func ArchiveDir added in v1.4.0

func ArchiveDir(srcDir string, dest Sink, opts ...ZipOption) error

ArchiveDir recursively adds contents of the directory to the archive and writes it to dest. See Archiver.ArchiveDir.

func ArchiveFiles added in v1.4.0

func ArchiveFiles(files []string, dest Sink, opts ...ZipOption) error

ArchiveFiles adds files to the archive and writes it to dest. See Archiver.ArchiveFiles.

func Clone added in v1.4.0

func Clone(zip Source, dest Sink, opts ...ZipOption) error

Clone copies archive with options using the default archiver. See Archiver.Clone.

func DecodeCP437 added in v1.2.0

func DecodeCP437(s string) string

DecodeCP437 converts CP437 (US DOS) string to UTF-8. This is the default fallback for ZIP archives.

func DecodeIBM866

func DecodeIBM866(s string) string

DecodeIBM866 converts CP866 (Cyrillic DOS) string to UTF-8.

func Exists added in v1.4.0

func Exists(zip Source, filename string) (bool, error)

Exists checks file existence. See Archiver.Exists.

func IsEncrypted added in v1.4.0

func IsEncrypted(zip Source, filters ...Filter) (bool, error)

IsEncrypted checks encryption using the default archiver. See Archiver.IsEncrypted.

func IsZipStream added in v1.4.0

func IsZipStream(r io.Reader) (bool, error)

IsZipStream checks if the data stream starts with the ZIP local header signature. This is a necessary condition for StreamReader to work, as it cannot scan the file for the central directory.

func Merge added in v1.4.0

func Merge(dest Sink, sources ...Source) error

Merge combines archives using the default archiver. See Archiver.Merge.

func ReadFile added in v1.4.0

func ReadFile(zip Source, filename string) ([]byte, error)

ReadFile reads file content using the default archiver. See Archiver.ReadFile.

func ReplaceFile added in v1.4.0

func ReplaceFile(zip Source, dest Sink, filename string, content io.Reader) error

ReplaceFile replaces a file. See Archiver.ReplaceFile

func SafePath added in v1.4.0

func SafePath(destDir, fileName string) (string, error)

SafePath returns a clean, absolute path for a zip entry within the destination directory. It ensures that the resulting path is inside the destDir (prevents Zip Slip).

func TotalSize added in v1.4.0

func TotalSize(zip Source, filters ...Filter) (uncompressed, compressed int64, err error)

TotalSize calculates sizes using the default archiver. See Archiver.TotalSize.

func Transform added in v1.4.0

func Transform(zip Source, dest Sink, fn TransformFunc, opts ...ZipOption) error

Transform modifies files on the fly. See Archiver.Transform

func Tree added in v1.4.0

func Tree(zip Source, filters ...Filter) (string, error)

Tree returns a string representation of the archive structure. See Archiver.Tree.

func Unzip added in v1.4.0

func Unzip(zip Source, destDir string, opts ...ZipOption) error

Unzip opens source zip and extracts its contents to dest directory. See Archiver.Unzip.

func UnzipFile added in v1.4.0

func UnzipFile(zip Source, filename string, dest Sink) error

UnzipFile extracts the specified file from the archive. See Archiver.UnzipFile.

func UnzipGlob added in v1.4.0

func UnzipGlob(zip Source, pattern, destDir string) error

UnzipGlob extracts all files file whose name matches the path.Match pattern. See Archiver.UnzipGlob.

func UnzipToMap added in v1.4.0

func UnzipToMap(zip Source, filters ...Filter) (map[string][]byte, error)

UnzipToMap loads archive content into memory. See Archiver.UnzipToMap.

func UnzipToTemp added in v1.4.0

func UnzipToTemp(zip Source, prefix string, opts ...ZipOption) (path string, cleanup func(), err error)

UnzipToTemp extracts to a temp dir. See Archiver.UnzipToTemp.

func UpdateMetadata added in v1.4.0

func UpdateMetadata(zip Source, dest Sink, modifier func(*File), opts ...ZipOption) error

UpdateMetadata modifies attributes. See Archiver.UpdateMetadata.

func UseSink added in v1.4.0

func UseSink(sink Sink, fn func(w io.Writer) error) (err error)

UseSink creates the destination writer and ensures it is closed properly.

func UseSource added in v1.4.0

func UseSource(src Source, fn func(r io.Reader, rAt io.ReaderAt, size int64) error) (err error)

UseSource opens the source, handles the ReaderAt vs Reader distinction, and ensures resources are closed properly after fn executes.

It passes:

  • r: The underlying stream (always non-nil).
  • rAt: The Random Access interface (non-nil if supported, e.g. File or Memory).
  • size: The total size (or SizeUnknown).

func Verify added in v1.4.0

func Verify(zip Source, opts ...ZipOption) error

Verify checks the integrity of the archive. See Archiver.Verify.

func Walk added in v1.4.0

func Walk(zip Source, walkFn func(*File) error, filters ...Filter) error

Walk iterates the archive. See Archiver.Walk.

Types

type AddOption

type AddOption func(f *File)

AddOption is a functional option for configuring file entries during addition.

func WithCompression

func WithCompression(c CompressionMethod, lvl int) AddOption

WithCompression sets the compression method and level for a regular file. Ignored for directories.

func WithConfig

func WithConfig(c FileConfig) AddOption

WithConfig applies a complete FileConfig, overwriting existing settings.

func WithEncryption

func WithEncryption(e EncryptionMethod, pwd string) AddOption

WithEncryption sets the encryption method and password for a regular file. Ignored for directories.

func WithMarkDirsImplicit added in v1.4.0

func WithMarkDirsImplicit() AddOption

WithMarkDirsImplicit marks added directories as implicit.

func WithName

func WithName(name string) AddOption

WithName overrides the destination filename within the archive. The name is automatically normalized to use forward slashes.

func WithPassword added in v1.3.0

func WithPassword(pwd string) AddOption

WithPassword sets the encryption password for a specific file. If no encryption method is specified, it defaults to AES256. Ignored for directories.

func WithPath

func WithPath(p string) AddOption

WithPath prepends a directory path to the file's name. The path is automatically normalized to use forward slashes.

type ArchiveDiff added in v1.4.0

type ArchiveDiff struct {
	Added    []string // Files present only in B.
	Removed  []string // Files present only in A.
	Modified []string // Files with differing CRCs or sizes.
}

ArchiveDiff describes the differences between two archives.

func Diff added in v1.4.0

func Diff(srcA, srcB Source, filters ...Filter) (ArchiveDiff, error)

Diff compares archives. See Archiver.Diff

type ArchiveOption added in v1.4.0

type ArchiveOption func(*Zip)

ArchiveOption is a function option for configuring archive creation

func WithCompressor added in v1.4.0

func WithCompressor(method CompressionMethod, factory CompressorFactory) ArchiveOption

WithCompressor registers a custom compression algorithm for this archive instance.

func WithDecompressor added in v1.4.0

func WithDecompressor(method CompressionMethod, d Decompressor) ArchiveOption

WithDecompressor registers a custom decompression algorithm.

func WithImplicitDirs added in v1.4.0

func WithImplicitDirs() ArchiveOption

WithImplicitDirs enables writing implicit dirs to the resulting archive.

func WithStrategy added in v1.4.0

func WithStrategy(s ZipStrategy) ArchiveOption

WithStrategy sets the parallel write strategy for the archive.

func WithZipCompression added in v1.4.0

func WithZipCompression(c CompressionMethod, lvl int) ArchiveOption

WithCompression sets the compression method and level for a regular file.

func WithZipConfig added in v1.4.0

func WithZipConfig(cfg ZipConfig) ArchiveOption

WithZipConfig applies the complete ZipConfig to the archive.

func WithZipEncryption added in v1.4.0

func WithZipEncryption(e EncryptionMethod, pwd string) ArchiveOption

WithPassword sets the encryption password for the archive.

func WithZipPassword added in v1.4.0

func WithZipPassword(pwd string) ArchiveOption

WithArchivePasswords sets global password for the archive. If no encryption method is specified, it defaults to AES256.

type Archiver added in v1.4.0

type Archiver struct {
	// contains filtered or unexported fields
}

Archiver provides a configurable environment for working with ZIP archives. It is build on top of Zip and reduces boilerplate code for common operations. By default, it supports the Store (no compression) and Deflate compression methods.

func NewArchiver added in v1.4.0

func NewArchiver(opts ...ArchiveOption) *Archiver

NewArchiver creates a new Archiver instance build on top of Zip with the specified options.

func (*Archiver) ArchiveDir added in v1.4.0

func (a *Archiver) ArchiveDir(srcDir string, destZip Sink, opts ...ZipOption) error

ArchiveDir recursively archives the contents of a directory. By default: Deflate compression, relative paths are preserved.

func (*Archiver) ArchiveDirWithContext added in v1.4.0

func (a *Archiver) ArchiveDirWithContext(ctx context.Context, srcDir string, destZip Sink, opts ...ZipOption) error

ArchiveDirWithContext recursively adds contents of the directory with context support. Cancelling the context stops processing remaining files and closes the destination file.

func (*Archiver) ArchiveFiles added in v1.4.0

func (a *Archiver) ArchiveFiles(files []string, destZip Sink, opts ...ZipOption) error

ArchiveFiles archives a list of files. File paths are "flattened" and placed in the root of the archive.

func (*Archiver) ArchiveFilesWithContext added in v1.4.0

func (a *Archiver) ArchiveFilesWithContext(ctx context.Context, files []string, destZip Sink, opts ...ZipOption) error

ArchiveFilesWithContext creates an archive from a list of files with context support.

func (*Archiver) Clone added in v1.4.0

func (a *Archiver) Clone(zip Source, destZip Sink, opts ...ZipOption) error

Clone copies the archive with the possibility of applying filters or modifiers. Example: deleting files, changing compression. Returns ErrNotImplemented if source is io.Reader.

func (*Archiver) CloneWithContext added in v1.4.0

func (a *Archiver) CloneWithContext(ctx context.Context, zip Source, destZip Sink, opts ...ZipOption) error

CloneWithContext copies archive with context support.

func (*Archiver) Diff added in v1.4.0

func (a *Archiver) Diff(srcA, srcB Source, filters ...Filter) (ArchiveDiff, error)

Diff compares two archives and returns the differences.

func (*Archiver) DiffWithContext added in v1.4.0

func (a *Archiver) DiffWithContext(ctx context.Context, zipA, zipB Source, filters ...Filter) (diff ArchiveDiff, err error)

DiffWithContext compares two archives and returns the differences with context support.

func (*Archiver) Exists added in v1.4.0

func (a *Archiver) Exists(zip Source, filename string) (bool, error)

Exists checks for the presence of a file in the archive.

func (*Archiver) ExistsWithContext added in v1.4.0

func (a *Archiver) ExistsWithContext(ctx context.Context, zip Source, filename string) (bool, error)

ExistsWithContext checks if a file exists with context support.

func (*Archiver) GetEntries added in v1.4.0

func (a *Archiver) GetEntries(zip Source) ([]*File, error)

GetEntries returns a list of files in the archive without loading their contents. If source is io.Reader, the returned files cannot be opened.

func (*Archiver) GetEntriesWithContext added in v1.4.0

func (a *Archiver) GetEntriesWithContext(ctx context.Context, zip Source) ([]*File, error)

GetEntriesWithContext lists files with context support.

func (*Archiver) IsEncrypted added in v1.4.0

func (a *Archiver) IsEncrypted(zip Source, filters ...Filter) (bool, error)

IsEncrypted checks if the archive contains at least one encrypted file.

func (*Archiver) Merge added in v1.4.0

func (a *Archiver) Merge(destZip Sink, sources ...Source) error

Merge combines multiple archives into one. Conflict resolution strategy: "the last written file wins". Returns ErrNotImplemented if source is io.Reader.

func (*Archiver) MergeWithContext added in v1.4.0

func (a *Archiver) MergeWithContext(ctx context.Context, destZip Sink, sources ...Source) error

MergeWithContext combines archives with context support.

func (*Archiver) ReadFile added in v1.4.0

func (a *Archiver) ReadFile(zip Source, filename string) ([]byte, error)

ReadFile reads the contents of a file from the archive into a byte slice.

func (*Archiver) ReadFileWithContext added in v1.4.0

func (a *Archiver) ReadFileWithContext(ctx context.Context, zip Source, filename string) ([]byte, error)

ReadFileWithContext reads file content with context support. Cancelling the context stops the reading process.

func (*Archiver) ReplaceFile added in v1.4.0

func (a *Archiver) ReplaceFile(zip Source, dest Sink, filename string, content io.Reader) error

ReplaceFile replaces a file in the archive with new content. The other files are copied without changes.

func (*Archiver) ReplaceFileWithContext added in v1.4.0

func (a *Archiver) ReplaceFileWithContext(ctx context.Context, zip Source, dest Sink, filename string, content io.Reader) error

ReplaceFileWithContext replaces a file in the archive with new content with context support.

func (*Archiver) Search added in v1.4.0

func (a *Archiver) Search(zip Source, text string, filters ...Filter) ([]*File, error)

Search searches for text within the contents of all files in the archive. It returns a list of files containing the text. Warning: this is a resource-intensive operation, as it unpacks each file.

func (*Archiver) SearchWithContext added in v1.4.0

func (a *Archiver) SearchWithContext(ctx context.Context, zip Source, text string, filters ...Filter) ([]*File, error)

SearchWithContext scans content with context support.

func (*Archiver) TotalSize added in v1.4.0

func (a *Archiver) TotalSize(zip Source, filters ...Filter) (uncompressed, compressed int64, err error)

TotalSize returns the total size of compressed and uncompressed data in the archive.

func (*Archiver) Transform added in v1.4.0

func (a *Archiver) Transform(zip Source, dest Sink, fn TransformFunc, opts ...ZipOption) error

Transform applies a function to each file in the archive, allowing modification of content. Example: Replace all occurrences of "old" with "new" in text files:

err := archive.Transform(src, dest, func(f *File) (io.Reader, error) {
    if strings.HasSuffix(f.Name(), ".txt") {
        return strings.NewReader(strings.ReplaceAll(f.Content(), "old", "new")), nil
    }
    return nil, nil // Keep original content
})

Returns ErrNotImplemented if source is io.Reader.

func (*Archiver) TransformWithContext added in v1.4.0

func (a *Archiver) TransformWithContext(ctx context.Context, zip Source, dest Sink, fn TransformFunc, opts ...ZipOption) error

TransformWithContext applies a function to each file in the archive, allowing modification of content with context support.

func (*Archiver) Tree added in v1.4.0

func (a *Archiver) Tree(zip Source, filters ...Filter) (string, error)

Tree returns a text representation of the archive structure (similar to the `tree` command).

func (*Archiver) TreeWithContext added in v1.4.0

func (a *Archiver) TreeWithContext(ctx context.Context, zip Source, filters ...Filter) (string, error)

Tree returns a string representation of the archive structure with context support.

func (*Archiver) Unzip added in v1.4.0

func (a *Archiver) Unzip(zip Source, destDir string, opts ...ZipOption) error

Unzip extracts the archive to the specified directory. If source is io.Reader, zip options do not apply.

func (*Archiver) UnzipFile added in v1.4.0

func (a *Archiver) UnzipFile(zip Source, filename string, dest Sink) error

UnzipFile extracts the specified file from the archive.

func (*Archiver) UnzipFileWithContext added in v1.4.0

func (a *Archiver) UnzipFileWithContext(ctx context.Context, zip Source, filename string, dest Sink) error

UnzipFileWithContext extracts the specified file from the archive with context support.

func (*Archiver) UnzipGlob added in v1.4.0

func (a *Archiver) UnzipGlob(zip Source, pattern, destDir string) error

UnzipGlob extracts all files file whose name matches the path.Match pattern.

func (*Archiver) UnzipGlobWithContext added in v1.4.0

func (a *Archiver) UnzipGlobWithContext(ctx context.Context, zip Source, pattern, destDir string) (err error)

UnzipGlobWithContext extracts all files file whose name matches the path.Match pattern with context support.

func (*Archiver) UnzipToMap added in v1.4.0

func (a *Archiver) UnzipToMap(zip Source, filters ...Filter) (map[string][]byte, error)

UnzipToMap extracts all files from the archive into a map[filename]content. Directories are ignored.

func (*Archiver) UnzipToMapWithContext added in v1.4.0

func (a *Archiver) UnzipToMapWithContext(ctx context.Context, zip Source, filters ...Filter) (map[string][]byte, error)

UnzipToMap extracts all files from the archive into a map[filename]content with context support.

func (*Archiver) UnzipToTemp added in v1.4.0

func (a *Archiver) UnzipToTemp(zip Source, prefix string, opts ...ZipOption) (path string, cleanup func(), err error)

UnzipToTemp unpacks the archive into a temporary directory. It returns the path and a cleanup function. It is the caller's responsibility to call cleanup().

func (*Archiver) UnzipToTempWithContext added in v1.4.0

func (a *Archiver) UnzipToTempWithContext(ctx context.Context, zip Source, prefix string, opts ...ZipOption) (path string, cleanup func(), err error)

UnzipToTempWithContext extracts the archive to a temporary directory with cancellation support.

func (*Archiver) UnzipWithContext added in v1.4.0

func (a *Archiver) UnzipWithContext(ctx context.Context, zip Source, destDir string, opts ...ZipOption) error

UnzipWithContext extracts archive contents with context support. Cancelling the context stops the extraction immediately.

func (*Archiver) UpdateMetadata added in v1.4.0

func (a *Archiver) UpdateMetadata(zip Source, dest Sink, modifier func(*File), opts ...ZipOption) error

UpdateMetadata modifies the metadata of files in the archive. Example: normalizing access permissions, adding comments. Returns ErrNotImplemented if source is io.Reader.

func (*Archiver) UpdateMetadataWithContext added in v1.4.0

func (a *Archiver) UpdateMetadataWithContext(ctx context.Context, zip Source, dest Sink, modifier func(*File), opts ...ZipOption) error

UpdateMetadataWithContext allows bulk modification with context support.

func (*Archiver) Verify added in v1.4.0

func (a *Archiver) Verify(zip Source, opts ...ZipOption) error

Verify checks the integrity of the files in the archive (CRC, checksums). If source is io.Reader, zip options do not apply.

func (*Archiver) VerifyWithContext added in v1.4.0

func (a *Archiver) VerifyWithContext(ctx context.Context, zip Source, opts ...ZipOption) error

Verify checks the integrity of the files in the archive with context support.

func (*Archiver) Walk added in v1.4.0

func (a *Archiver) Walk(zip Source, walkFn func(*File) error, filters ...Filter) error

Walk traverses all files in the archive, calling walkFn for each one. If walkFn returns an error, the traversal stops.

func (*Archiver) WalkWithContext added in v1.4.0

func (a *Archiver) WalkWithContext(ctx context.Context, zip Source, walkFn func(*File) error, filters ...Filter) (err error)

WalkWithContext iterates over the archive with context cancellation support.

type CompressionMethod

type CompressionMethod uint16

CompressionMethod represents the compression algorithm used for a file in the ZIP archive

const (
	Store     CompressionMethod = 0  // No compression - file stored as-is
	Deflate   CompressionMethod = 8  // DEFLATE compression (most common)
	Deflate64 CompressionMethod = 9  // DEFLATE64(tm) - Not supported natively
	BZIP2     CompressionMethod = 12 // BZIP2 - Not supported natively
	LZMA      CompressionMethod = 14 // LZMA - Not supported natively
	ZStandard CompressionMethod = 93 // Zstandard - Not supported natively
)

Supported compression methods according to ZIP specification. Note: This library natively supports Store (0) and Deflate (8). Other methods require registering custom compressors via RegisterCompressor.

type Compressor

type Compressor interface {
	// Compress reads from src and writes compressed data to dest.
	// Returns the number of uncompressed bytes read.
	Compress(src io.Reader, dest io.Writer) (int64, error)
}

Compressor transforms raw data into compressed data.

func NewDeflateCompressor

func NewDeflateCompressor(level int) Compressor

NewDeflateCompressor creates a reusable compressor for a specific level.

type CompressorFactory added in v1.2.0

type CompressorFactory func(level int) Compressor

CompressorFactory creates a Compressor instance for a specific compression level. The level parameter is typically 0-9, but interpretations vary by algorithm. Implementations should normalize invalid levels to defaults.

type ConflictAction added in v1.4.0

type ConflictAction int

ConflictAction defines the decision taken when a file name collision occurs during Zip.Load.

const (
	// ActionReplace overwrites the existing entry with the new one (Default).
	ActionReplace ConflictAction = iota

	// ActionSkip ignores the new entry, keeping the existing one.
	ActionSkip

	// ActionError reports [ErrDuplicateEntry] and skips the new entry.
	ActionError

	// ActionRename adds the new entry under a different name provided by the resolver.
	ActionRename
)

func DefaultConflictHandler added in v1.4.0

func DefaultConflictHandler(_, _ *File) (ConflictAction, string)

DefaultConflictHandler replaces existing files (Last Write Wins).

func ErrorConflictHandler added in v1.4.0

func ErrorConflictHandler(_, _ *File) (ConflictAction, string)

ErrorConflictHandler treats duplicates as errors.

func SkipConflictHandler added in v1.4.0

func SkipConflictHandler(_, _ *File) (ConflictAction, string)

SkipConflictHandler keeps existing files and ignores new ones.

func UpdateConflictHandler added in v1.4.0

func UpdateConflictHandler(existing, new *File) (ConflictAction, string)

UpdateConflictHandler replaces the file only if the new one is newer (ModTime).

type ConflictHandler added in v1.4.0

type ConflictHandler func(existing, new *File) (ConflictAction, string)

ConflictHandler determines how to handle name collisions. It receives the existing file (already in archive) and the new file (being loaded). It returns the action to take and an optional new name (used only with ActionRename).

type Decompressor

type Decompressor interface {
	// Decompress returns a stream of uncompressed data.
	Decompress(src io.Reader) (io.ReadCloser, error)
}

Decompressor transforms compressed data back into raw data.

type DeflateCompressor

type DeflateCompressor struct {
	// contains filtered or unexported fields
}

DeflateCompressor implements DEFLATE compression with memory pooling.

func (*DeflateCompressor) Compress

func (d *DeflateCompressor) Compress(src io.Reader, dest io.Writer) (int64, error)

type DeflateDecompressor

type DeflateDecompressor struct{}

DeflateDecompressor implements the "Deflate" method.

func (*DeflateDecompressor) Decompress

func (dd *DeflateDecompressor) Decompress(src io.Reader) (io.ReadCloser, error)

type EncryptionMethod

type EncryptionMethod uint16

EncryptionMethod represents the encryption algorithm used for file protection.

Compatibility Warning:

  • AES256 is the recommended standard for security. It is supported by modern archivers like 7-Zip, WinRAR.
  • Some legacy tools (e.g., older built-in macOS Archive Utility or Windows Explorer) may only support ZipCrypto (weak encryption). Use ZipCrypto only if legacy compatibility is strictly required.
const (
	NotEncrypted EncryptionMethod = 0 // No encryption - file stored in plaintext
	ZipCrypto    EncryptionMethod = 1 // Legacy encryption. Vulnerable to brute force attacks
	AES256       EncryptionMethod = 2 // Modern AES256 encryption
)

Supported encryption methods

type File

type File struct {
	// contains filtered or unexported fields
}

File represents a file entry within a ZIP archive, encapsulating both metadata and content access mechanisms. Each File object corresponds to one entry in the ZIP central directory and can represent either a regular file or a directory.

func GetEntries added in v1.4.0

func GetEntries(zip Source) ([]*File, error)

GetEntries lists files using the default archiver. Archiver.GetEntries

func NewFile added in v1.4.0

func NewFile(name string, isDir bool) (*File, error)

NewFile creates a detached File entry with manual metadata. Note: The file is not attached to any archive until you call Zip.Add. You must set a data source via File.WithOpenFunc before writing, unless it's a directory.

func Search(zip Source, text string, filters ...Filter) ([]*File, error)

Search grep content. See Archiver.Search.

func SortFilesOptimized

func SortFilesOptimized(files []*File, strategy FileSortStrategy) []*File

SortFilesOptimized returns a sorted slice of files according to the strategy. Returns a new slice; the original slice is not modified.

func (*File) CRC32

func (f *File) CRC32() uint32

CRC32 returns the CRC-32 checksum of the uncompressed file data.

func (*File) CompressedSize

func (f *File) CompressedSize() int64

CompressedSize returns the size of the compressed data within the archive.

func (*File) Config added in v1.1.0

func (f *File) Config() FileConfig

Config returns archive file entry configuration.

func (*File) FillSnapshot added in v1.4.0

func (f *File) FillSnapshot(snap *FileSnapshot)

FillSnapshot executes the passed data snapshot to avoid allocations.

func (*File) FsTime added in v1.1.0

func (f *File) FsTime() (mtime, atime, ctime time.Time)

FsTime returns the file timestamps (Modification, Access, Creation) if available.

func (*File) GetExtraField

func (f *File) GetExtraField(tag uint16) []byte

GetExtraField retrieves the raw bytes of an extra field by its tag ID.

func (*File) HasExtraField

func (f *File) HasExtraField(tag uint16) bool

HasExtraField checks whether an extra field with the specified tag exists.

func (*File) HostSystem added in v1.1.0

func (f *File) HostSystem() sys.HostSystem

HostSystem returns the system file was created in.

func (*File) IsDir

func (f *File) IsDir() bool

IsDir returns true if the file represents a directory entry.

func (*File) IsEncrypted added in v1.4.0

func (f *File) IsEncrypted() bool

IsEncrypted checks wether the data from the original archive is encrypted.

func (*File) IsImplicit added in v1.4.0

func (f *File) IsImplicit() bool

IsImplicit returns true if the entry was created automatically and is not associated with a real directory.

func (*File) LocalHeaderOffset added in v1.4.0

func (f *File) LocalHeaderOffset() int64

LocalHeaderOffset returns file entry offset inside the archive.

func (*File) ModTime

func (f *File) ModTime() time.Time

ModTime returns the file's last modification timestamp.

func (*File) Mode added in v1.1.0

func (f *File) Mode() fs.FileMode

Mode returns underlying file attributes.

func (*File) Name

func (f *File) Name() string

Name returns the file's path within the ZIP archive.

func (*File) Open

func (f *File) Open() (io.ReadCloser, error)

Open returns an io.ReadCloser for reading the uncompressed content of the file. If the file comes from an existing archive, the source config is used.

Returns an error if the file is a directory or has no data source. ErrPasswordMismatch is returned immediately if the provided password is incorrect. The returned ReadCloser may return ErrChecksum during reading (typically at EOF) or upon Close() if the data integrity check fails.

func (*File) OpenRaw added in v1.4.0

func (f *File) OpenRaw() (*io.SectionReader, error)

OpenRaw returns an io.SectionReader for reading the raw file content (compressed and/or encrypted) directly from the archive source. If the file is encrypted (AES), the reader includes Salt, PVV, and MAC bytes. Returns error if the file source is not available.

func (*File) RequiresZip64

func (f *File) RequiresZip64() bool

RequiresZip64 determines whether this file requires ZIP64 format extensions.

func (*File) SetExtraField

func (f *File) SetExtraField(tag uint16, data []byte) error

SetExtraField adds or replaces an extra field entry for this file. Returns an error if adding the field would exceed the maximum extra field length.

func (*File) Snapshot added in v1.4.0

func (f *File) Snapshot() *FileSnapshot

Snapshot creates an immutable copy of the file's metadata.

func (*File) UncompressedSize

func (f *File) UncompressedSize() int64

UncompressedSize returns the size of the original file content before compression.

func (*File) WithComment added in v1.4.0

func (f *File) WithComment(c string) *File

func (*File) WithCompression added in v1.4.0

func (f *File) WithCompression(method CompressionMethod, level int) *File

WithCompression replaces the compression method and level with the specified ones. This does not affect configuration for decompressing file from an existing archive.

func (*File) WithConfig added in v1.4.0

func (f *File) WithConfig(c FileConfig) *File

WithConfig applies a FileConfig to this file, overriding individual properties.

func (*File) WithDisableEncryption added in v1.4.0

func (f *File) WithDisableEncryption() *File

WithDisableEncryption sets encryption method to NotEncrypted and removes the password for this file. This does not affect configuration for decompressing file from an existing archive.

func (*File) WithEncryption added in v1.4.0

func (f *File) WithEncryption(method EncryptionMethod, pwd string) *File

WithEncryption replaces the encryption method and password with the specified ones. This does not affect configuration for decompressing file from an existing archive.

func (*File) WithModTime added in v1.4.0

func (f *File) WithModTime(modTime time.Time) *File

WithModTime sets the file's last modification time.

func (*File) WithMode added in v1.4.0

func (f *File) WithMode(mode fs.FileMode) *File

WithMode updates the Unix-style file permission bits.

func (*File) WithOpenFunc added in v1.4.0

func (f *File) WithOpenFunc(openFunc func() (io.ReadCloser, error)) *File

WithOpenFunc replaces the function used to open the file's content.

func (*File) WithPassword added in v1.4.0

func (f *File) WithPassword(pwd string) *File

SetSourcePassword updates the password used to encrypt/decrypt this specific file. If current encryption is NotEncrypted it defaults to AES256.

func (*File) WithSourcePassword added in v1.4.0

func (f *File) WithSourcePassword(pwd string) *File

WithSourcePassword updates the password used to read (decrypt) this specific file from the original archive in case if the archive-wide password was incorrect or if different files have different passwords.

func (*File) WithUncompressedSize added in v1.4.0

func (f *File) WithUncompressedSize(size int64) *File

SetUncompressed size sets the file uncompressed size atomically.

type FileConfig

type FileConfig struct {
	// CompressionMethod overrides the global default.
	CompressionMethod CompressionMethod

	// CompressionLevel overrides the global default.
	CompressionLevel int

	// EncryptionMethod overrides the global default.
	EncryptionMethod EncryptionMethod

	// Password overrides the global archive password for this file.
	Password string

	// Comment is a file-specific comment (max 65535 bytes).
	Comment string
}

FileConfig defines configuration specific to a single archive entry. It overrides the global ZipConfig.

type FileError added in v1.4.0

type FileError struct {
	Op   string // Operation that failed (e.g., "open", "write", "extract")
	File *File  // The file entry that caused the error
	Err  error  // The actual error (sentinel error)
}

FileError wraps an error with context about a specific file entry.

func (*FileError) Error added in v1.4.0

func (e *FileError) Error() string

func (*FileError) Unwrap added in v1.4.0

func (e *FileError) Unwrap() error

Unwrap allows errors.Is and errors.As to work with the underlying error.

type FileSnapshot added in v1.4.0

type FileSnapshot struct {
	Name       string
	IsDir      bool
	IsImplicit bool
	Mode       fs.FileMode
	ModTime    time.Time
	HostSystem sys.HostSystem

	// Configuration (Snapshot of FileConfig)
	Config FileConfig

	// State (Values read from atomics at the moment of snapshot)
	UncompressedSize  int64
	CompressedSize    int64
	LocalHeaderOffset int64
	CRC32             uint32
	Flags             uint16

	// Extra Fields (Deep copy or flattened representation)
	Metadata      sys.Metadata
	ExtraField    map[uint16][]byte
	ExtraFieldRaw []byte
	// contains filtered or unexported fields
}

FileSnapshot represents an immutable point-in-time copy of File metadata.

func (*FileSnapshot) CentralDirectory added in v1.4.0

func (s *FileSnapshot) CentralDirectory() internal.CentralDirectory

CentralDirectory generates the central directory entry for this file.

func (*FileSnapshot) CompressionLevelBits added in v1.4.0

func (s *FileSnapshot) CompressionLevelBits() uint16

func (*FileSnapshot) CompressionMethod added in v1.4.0

func (s *FileSnapshot) CompressionMethod() uint16

func (*FileSnapshot) ExternalFileAttributes added in v1.4.0

func (s *FileSnapshot) ExternalFileAttributes() uint32

func (*FileSnapshot) FileBitFlag added in v1.4.0

func (s *FileSnapshot) FileBitFlag() uint16

func (*FileSnapshot) LocalHeader added in v1.4.0

func (s *FileSnapshot) LocalHeader() internal.LocalFileHeader

LocalHeader generates the local file header that precedes the file data.

func (*FileSnapshot) RequiresZip64 added in v1.4.0

func (s *FileSnapshot) RequiresZip64() bool

RequiresZip64 checks if Zip64 format is needed based on the snapshot values.

func (*FileSnapshot) ResetEncodeOptions added in v1.4.0

func (s *FileSnapshot) ResetEncodeOptions()

ResetEncodeOptions resets file encode options to default

func (*FileSnapshot) VersionMadeBy added in v1.4.0

func (s *FileSnapshot) VersionMadeBy() uint16

func (*FileSnapshot) VersionNeededToExtract added in v1.4.0

func (s *FileSnapshot) VersionNeededToExtract() uint16

type FileSortStrategy

type FileSortStrategy int

FileSortStrategy defines the order in which files are written to the archive. Choosing the right strategy can optimize writing speed (CPU parallelism), memory usage or archive structure (ZIP64 overhead).

const (
	SortDefault         FileSortStrategy = iota
	SortLargeFilesLast                   // Large files (>=4GB) at end
	SortLargeFilesFirst                  // Large files (>=4GB) at start
	SortSizeAscending                    // Smallest first
	SortSizeDescending                   // Largest first
	SortZIP64Optimized                   // Buckets: <10MB, <4GB, >=4GB (each sorted Asc)
	SortAlphabetical                     // A-Z by filename
)

type Filter added in v1.4.0

type Filter func(file *File) bool

Filter filters out the files.

func FilterExcludeDir added in v1.4.0

func FilterExcludeDir(dirPath string) Filter

FilterExcludeDir returns files without a provided directory and its contents.

func FilterFromDir added in v1.4.0

func FilterFromDir(dirPath string) Filter

FilterFromDir returns only files nested under the specified path.

func FilterOnly added in v1.4.0

func FilterOnly(files []*File) Filter

WithFiles returns files provided.

type ProgressStats added in v1.4.0

type ProgressStats struct {
	CurrentFile    *File // Currently processed file
	CurrentRead    int64 // Uncompressed bytes read from current file
	CurrentWritten int64 // Bytes produced for current file
	ExpectedRead   int64 // Sum of uncompressed file sizes
	TotalRead      int64 // Total uncompressed bytes read so far
	TotalWritten   int64 // Total compressed bytes produced so far
	ArchiveWritten int64 // Total bytes written to dest (headers + data + CD)
	TotalFiles     int64 // Total amount of files to process
	ProcessedFiles int64 // The total number of files processed, including errors.
	Errors         int64 // Failed files count
}

ProgressStats contains detailed information about the current progress of the operation.

type ResourceLimits added in v1.4.0

type ResourceLimits struct {
	// MaxTotalSize is the maximum allowed bytes to write to disk for the whole operation.
	// Default: 0 (unlimited).
	MaxTotalSize int64

	// MaxFileSize is the maximum allowed size for a single file.
	// Default: 0 (unlimited).
	MaxFileSize int64

	// MaxCompressionRatio is the maximum allowed ratio between uncompressed and compressed size.
	// E.g., 100 means uncompressed data cannot be more than 100x larger than compressed.
	// Default: 0 (disabled). Recommended: 100-200.
	MaxRatio float64
}

ResourceLimits defines constraints for extraction.

type SecuritySettings added in v1.4.0

type SecuritySettings struct {
	// AllowSymlinks enables extraction of symbolic links.
	// WARNING: disabling this is recommended for untrusted archives.
	// Default: false.
	AllowSymlinks bool

	// MinEncryption allows enforcing a minimum encryption standard.
	// e.g. Require AES256 to prevent downgrade attacks.
	MinEncryption EncryptionMethod

	// ResourceLimits defines constraints for extraction.
	ResourceLimits ResourceLimits
}

SecuritySettings define extraction safety configuration.

type Sink added in v1.4.0

type Sink interface {
	Create() (io.Writer, error)
	Close() error
}

Sink provides an interface for writing a ZIP archive. Implementations must support file creation and closing.

func ToFile added in v1.4.0

func ToFile(f *os.File) Sink

ToFile creates a Sink for writing to an open *os.File file. The file is not closed after the operation.

func ToFilePath added in v1.4.0

func ToFilePath(path string) Sink

ToFilePath creates a Sink for writing to a file at the specified path.

func ToURL added in v1.4.0

func ToURL(url, method string, client *http.Client) Sink

ToURL creates a Sink that streams the generated ZIP archive directly to a URL. If method is empty, it defaults to http.MethodPut.

func ToWriter added in v1.4.0

func ToWriter(w io.Writer) Sink

ToWriter creates a Sink for writing to an io.Writer.

type Source added in v1.4.0

type Source interface {
	Open() (io.Reader, int64, error)
	Close() error
}

Source provides an interface for reading a ZIP archive. Implementations must support multiple reads (for example, via io.ReaderAt).

func FromFile added in v1.4.0

func FromFile(f *os.File) Source

FromFile creates a Source from an opened *os.File file. The file is not closed after the operation.

func FromFilePath added in v1.4.0

func FromFilePath(path string) Source

FromFilePath creates a Source from a file at the specified path.

func FromReaderAt added in v1.4.0

func FromReaderAt(r io.ReaderAt, size int64) Source

FromReaderAt creates a Source from an io.ReaderAt with a known size.

func FromStream added in v1.4.0

func FromStream(r io.Reader, size int64) Source

FromStream creates source from an io.Reader with a known size.

func FromURL added in v1.4.0

func FromURL(url string, client *http.Client) Source

FromURL creates a Source for reading a ZIP archive over HTTP. Requirements: the server must support the "Range" header (Accept-Ranges: bytes). It uses HTTP Range Requests to read only the necessary parts of the archive.

type StreamOption added in v1.4.0

type StreamOption func(s *StreamReader)

StreamOption applies the option to StreamReader.

func WithStreamConfig added in v1.4.0

func WithStreamConfig(cfg ZipConfig) StreamOption

WithStreamConfig sets the stream config.

type StreamReader added in v1.4.0

type StreamReader struct {
	// contains filtered or unexported fields
}

StreamReader reads a ZIP archive sequentially from an io.Reader.

Unlike the standard Zip struct (which requires io.ReaderAt), StreamReader does not need random access to the data source. This makes it ideal for processing ZIP archives from network streams (e.g., HTTP response bodies) or pipes without buffering the entire file to disk or memory.

Limitations:

  • Since it reads Local File Headers instead of the Central Directory, metadata usually stored at the end of the archive is incomplete.
  • You can only read files in the order they appear in the stream. You cannot go back to a previous file.

func NewStreamReader added in v1.4.0

func NewStreamReader(src io.Reader, opts ...StreamOption) *StreamReader

NewStreamReader returns a new StreamReader reading from source.

func (*StreamReader) ExtractFile added in v1.4.0

func (sr *StreamReader) ExtractFile(fpath string) error

func (*StreamReader) ExtractTo added in v1.4.0

func (sr *StreamReader) ExtractTo(destDir string) error

ExtractTo unpacks the archive to the specified destination directory. Attempts to extract files outside the target directory will result in ErrInsecurePath.

func (*StreamReader) ExtractToWithContext added in v1.4.0

func (sr *StreamReader) ExtractToWithContext(ctx context.Context, destDir string) error

ExtractToWithContext extracts files with context support. Context cancellation stops the extraction process.

func (*StreamReader) Next added in v1.4.0

func (sr *StreamReader) Next() (*File, error)

Next advances to the next entry in the ZIP archive. The CRC32 checksum is verified only after the stream is fully consumed.

Returns the next File entry or io.EOF if the end of the archive is reached. If the previous file's data was not fully read, Next automatically discards the remaining bytes to reach the next header. The returned file should not be opened manually, but rather using StreamReader.Open.

Warning: The returned File object is populated from the Local File Header. Fields like Unix permissions, file comments, or precise NTFS timestamps are unavailable.

func (*StreamReader) Open added in v1.4.0

func (sr *StreamReader) Open() (io.ReadCloser, error)

Open returns an io.ReadCloser that provides access to the decompressed content of the current file. It must be called after a successful StreamReader.Next and it be called only once per file. Closing the returned ReadCloser is optional for the library's internal state, but recommended to free resources immediately. Returns error if no file is currently selected.

func (*StreamReader) OpenRaw added in v1.4.0

func (sr *StreamReader) OpenRaw() (io.Reader, error)

OpenRaw returns an io.Reader for reading the raw content (compressed and/or encrypted) directly from the currently opened file. If the file is encrypted (AES256), the reader includes Salt, PVV, and MAC bytes.

func (*StreamReader) RegisterDecompressor added in v1.4.0

func (sr *StreamReader) RegisterDecompressor(method CompressionMethod, d Decompressor)

RegisterDecompressor adds support for reading a custom compression method. See DeflateDecompressor for implementation example.

func (*StreamReader) Scan added in v1.4.0

func (sr *StreamReader) Scan(pattern string) (*File, error)

Scan searches for the next file whose name matches the path.Match pattern. It automatically skips all intermediate files. Returns ErrFileNotFound if there are no more matches.

func (*StreamReader) SetPassword added in v1.4.0

func (sr *StreamReader) SetPassword(pwd string)

SetPassword sets current password atomically.

func (*StreamReader) SetTextDecoder added in v1.4.0

func (sr *StreamReader) SetTextDecoder(td TextDecoder)

SetTextDecoder sets current TextDecoder atomically.

type TextDecoder

type TextDecoder func(string) string

TextDecoder is a function that converts raw binary string (interpreted as specific encoding) into UTF-8.

type TransformFunc added in v1.4.0

type TransformFunc func(f *File) (io.Reader, error)

TransformFunc defines the logic for modifying a file:

  • (newReader, nil): replace the content;
  • (nil, nil): leave unchanged;
  • (nil, ErrSkip): delete the file.

type Zip

type Zip struct {
	// contains filtered or unexported fields
}

Zip represents an in-memory ZIP archive manager. It is concurrency-safe and supports streaming, random access, and parallel operations.

By default it supports Store (no compression) and Deflate compression methods.

func NewZip

func NewZip(opts ...ArchiveOption) *Zip

NewZip creates a ready-to-use empty ZIP archive. Default support includes Store (No Compression) and Deflate.

func (*Zip) Add added in v1.4.0

func (z *Zip) Add(f *File, opts ...AddOption) error

Add adds a pre-configured File object to the archive. Paths are normalized to use forward slashes.

Unlike Zip.Load, add methods are strict: if a file with the same name already exists in the archive, they return ErrDuplicateEntry and do not overwrite the existing entry.

Options can be used to override compression, encryption, or file attributes.

func (*Zip) AddBytes

func (z *Zip) AddBytes(data []byte, filename string, opts ...AddOption) (*File, error)

AddBytes adds a file from a byte slice. Returns ErrFileEntry if an invalid argument is passed.

func (*Zip) AddDir added in v1.3.0

func (z *Zip) AddDir(path string, opts ...AddOption) ([]*File, error)

AddDir recursively adds contents of the directory to the archive. Files are added using "Best Effort" strategy: if a single file fails to read, AddDir continues processing others but returns a joined error at the end.

func (*Zip) AddFS added in v1.3.0

func (z *Zip) AddFS(fileSystem fs.FS, opts ...AddOption) ([]*File, error)

AddFS adds files from an fs.FS (e.g., embed.FS, os.DirFS) to the archive. It recursively walks the file system and adds all entries using "Best Effort" strategy.

func (*Zip) AddFile

func (z *Zip) AddFile(path string, opts ...AddOption) (*File, error)

AddFile adds a file from the local filesystem to the archive. Symlinks are stored as link targets and are not followed.

func (*Zip) AddLazy added in v1.3.0

func (z *Zip) AddLazy(name string, openFunc func() (io.ReadCloser, error), opts ...AddOption) (*File, error)

AddLazy adds a file entry whose content is opened only when writing the archive.

The io.ReadCloser returned by openFunc is automatically closed by the library after the file is written. You do not need to wrap it to close it manually, but you are responsible for closing any resources used to create that reader (e.g. database connections) inside the closure or after Zip.WriteTo finishes.

Returns ErrFileEntry if an invalid name is passed.

func (*Zip) AddOSFile added in v1.2.0

func (z *Zip) AddOSFile(f *os.File, opts ...AddOption) (*File, error)

AddOSFile adds an open os.File to the archive. The file content is wrapped using io.SectionReader.

func (*Zip) AddReader

func (z *Zip) AddReader(r io.Reader, filename string, size int64, opts ...AddOption) (*File, error)

AddReader adds a file from an io.Reader stream.

If size is SizeUnknown and the target writer is an io.Seeker (e.g., os.File), the writer will buffer the entire stream to a temporary file to calculate headers before writing. To avoid this, provide the exact size if possible.

Returns ErrFileEntry if an invalid argument is passed.

func (*Zip) AddString

func (z *Zip) AddString(content string, filename string, opts ...AddOption) (*File, error)

AddString adds a file from a string. Returns ErrFileEntry if an invalid argument is passed.

func (*Zip) Config added in v1.4.0

func (z *Zip) Config() ZipConfig

Config returns current global zip configuration.

func (*Zip) Exists

func (z *Zip) Exists(name string) bool

Exists checks if a file or directory exists in the archive. Returns true if an exact file match is found.

func (*Zip) ExtractTo added in v1.4.0

func (z *Zip) ExtractTo(path string, opts ...ZipOption) error

ExtractTo unpacks the archive to the specified destination directory using "Best Effort" strategy. It automatically creates missing directory structures and restores file modification times and permissions. Attempts to extract files outside the target directory will result in ErrInsecurePath.

func (*Zip) ExtractToWithContext added in v1.4.0

func (z *Zip) ExtractToWithContext(ctx context.Context, path string, opts ...ZipOption) error

ExtractToWithContext extracts files with context support. Context cancellation stops the extraction process.

func (*Zip) FS added in v1.3.0

func (z *Zip) FS() fs.FS

FS returns fs.FS, a read-only virtual filesystem on top of the ZIP archive.

func (*Zip) File added in v1.2.0

func (z *Zip) File(name string) (*File, bool)

File returns the entry matching the given name and wether it exists. Name is case-sensitive. Paths are normalized to use forward slashes.

func (*Zip) Files added in v1.2.0

func (z *Zip) Files() []*File

Files returns a copy of the list of files in the archive.

func (*Zip) Find added in v1.2.0

func (z *Zip) Find(pattern string) ([]*File, error)

Find searches for files matching the pattern in all directories. Unlike Glob, the pattern "*" matches "/" characters. Example: Find("*.log") matches "error.log" and "var/logs/access.log".

func (*Zip) Glob added in v1.2.0

func (z *Zip) Glob(pattern string) ([]*File, error)

Glob returns all files file whose name matches the path.Match pattern.

func (*Zip) Load added in v1.2.0

func (z *Zip) Load(src io.ReaderAt, size int64) ([]*File, error)

Load parses an existing ZIP archive's central directory and merges its entries into the current Zip instance using "Best Effort" strategy. It supports standard ZIP, Zip64, and archives with preambles (e.g., self-extracting EXEs).

If the current archive already contains entries with the same name as in the source, the existing entries are replaced by the new ones by default. You can change logic by specifying custom [ZipConfig.ConflictHandler].

Returns ErrFormat if the source is not a valid ZIP archive.

func (*Zip) LoadFromFile added in v1.2.0

func (z *Zip) LoadFromFile(f *os.File) ([]*File, error)

LoadFromFile parses a ZIP from a local os.File.

func (*Zip) LoadFromFileWithContext added in v1.3.0

func (z *Zip) LoadFromFileWithContext(ctx context.Context, f *os.File) ([]*File, error)

LoadFromFile parses a ZIP from a local os.File with context support.

func (*Zip) LoadWithContext added in v1.2.0

func (z *Zip) LoadWithContext(ctx context.Context, src io.ReaderAt, size int64) ([]*File, error)

LoadWithContext parses an archive with context support. Cancelling the context stops processing the remaining files.

func (*Zip) Mkdir added in v1.2.0

func (z *Zip) Mkdir(name string, opts ...AddOption) (*File, error)

Mkdir creates an explicit directory entry in the archive. Returns ErrFileEntry if invalid name is passed.

func (*Zip) Move added in v1.1.0

func (z *Zip) Move(old, newDir string) error

Move changes the directory location of an entry while preserving its base name. If target is a directory, the entire tree is moved recursively to the new location. Any missing parent directories in the destination path are automatically created. Example: Move("etc/file.txt", "backup/docs") -> "backup/docs/file.txt".

Like Zip.Rename, this operation is atomic. It validates all resulting child paths before modifying the archive structure.

Errors:

func (*Zip) OpenFile

func (z *Zip) OpenFile(name string) (io.ReadCloser, error)

OpenFile returns a ReadCloser for the named file within the archive. Returns ErrFileNotFound if not found or target is a directory.

func (*Zip) RegisterCompressor

func (z *Zip) RegisterCompressor(method CompressionMethod, factory CompressorFactory) *Zip

RegisterCompressor registers a factory function for a specific compression method. See NewDeflateCompressor for creating custom compressors.

func (*Zip) RegisterDecompressor

func (z *Zip) RegisterDecompressor(method CompressionMethod, d Decompressor) *Zip

RegisterDecompressor adds support for reading a custom compression method. See DeflateDecompressor for creating custom decompressors.

func (*Zip) Remove added in v1.3.0

func (z *Zip) Remove(name string) ([]*File, error)

Remove deletes an entry from the archive. If the target is a directory, it recursively removes all its contents and the directory entry itself.

Providing an empty string or "." results in a "Reset" operation: all entries are removed, and the archive becomes empty.

Returns ErrFileNotFound if no entries matched the provided name.

func (*Zip) Rename added in v1.1.0

func (z *Zip) Rename(old, newName string) error

Rename changes the name of an entry while preserving its current directory location. If target is a directory, it recursively renames all nested files and subdirectories to reflect the new parent name. Example: Rename("logs/old.txt", "new.txt") -> "logs/new.txt"

This operation is atomic. It performs a "dry run" check of all resulting paths. If any path (including children) exceeds ZIP limits or conflicts with existing entries, no changes are applied to the archive.

Errors:

func (*Zip) Select added in v1.4.0

func (z *Zip) Select(filters ...Filter) []*File

Select returns a list of files that satisfy the given condition.

func (*Zip) SetConfig

func (z *Zip) SetConfig(c ZipConfig) *Zip

SetConfig updates the global configuration atomically. The current password is applied to all loaded files.

func (*Zip) Verify added in v1.4.0

func (z *Zip) Verify(opts ...ZipOption) error

Verify checks the integrity of the archive files. It decompresses every file and verifies checksums/MACs without writing to disk.

func (*Zip) VerifyWithContext added in v1.4.0

func (z *Zip) VerifyWithContext(ctx context.Context, opts ...ZipOption) error

VerifyWithContext checks integrity with context cancellation.

func (*Zip) WriteHTTP added in v1.4.0

func (z *Zip) WriteHTTP(w http.ResponseWriter, filename string, opts ...ZipOption) error

WriteHTTP writes the archive to the HTTP response writer with correct headers.

If an error occurs before writing data (e.g. empty archive), it does not write headers, allowing the caller to send an HTTP 500/400.

If an error occurs during writing, the download will be truncated/corrupted (which is the only way to signal failure to the client after headers are sent). In this case, the error is returned for server-side logging.

func (*Zip) WriteHTTPWithContext added in v1.4.0

func (z *Zip) WriteHTTPWithContext(ctx context.Context, w http.ResponseWriter, filename string, opts ...ZipOption) error

func (*Zip) WriteTo added in v1.2.0

func (z *Zip) WriteTo(dest io.Writer, opts ...ZipOption) (int64, error)

WriteTo serializes the archive to the specified writer. Files are processes using "Best Effort" strategy. If the writer is io.Seeker, temporary files are used if size exceeds [ZipConfig.MemoryThreshold]).

Use WithWorkers option to speed the compression significantly. Speed scales efficiently with CPU cores for compression-heavy tasks (Deflate/AES). Peak memory usage is strictly bounded by the pipeline capacity (maxWorkers * 2) and the MemoryThreshold (default 10MB).

Efficiency Note: Processing files in descending order of size (SortSizeDescending) helps finish long-running compression tasks early and can stabilize memory usage, though it may be slightly slower for small archives.

Returns the total number of bytes written or an error if the operation fails.

func (*Zip) WriteToWithContext added in v1.2.0

func (z *Zip) WriteToWithContext(ctx context.Context, dest io.Writer, opts ...ZipOption) (int64, error)

WriteToWithContext writes the archive with context support. Cancelling the context stops processing the remaining files and results in a valid archive.

type ZipConfig

type ZipConfig struct {
	// CompressionMethod is the default algorithm for new files.
	CompressionMethod CompressionMethod

	// CompressionLevel controls the speed vs size trade-off (0-9).
	// 0 = Store (no compression), 9 = Best compression.
	CompressionLevel int

	// EncryptionMethod is the default encryption algorithm.
	// Recommended: [AES256].
	EncryptionMethod EncryptionMethod

	// Password is the default credentials for encrypting the archive.
	// If specified, defaults to [AES256] encryption.
	Password string

	// Comment is the archive-level comment (max 65535 bytes).
	Comment string

	// FileSortStrategy determines the order of file
	// processing and their order in the written archive.
	FileSortStrategy FileSortStrategy

	// ZipStrategy determines what parallel write strategy to use. By default
	// the order of files in the written archive is not deterministic.
	ZipStrategy ZipStrategy

	// ConflictHandler defines the strategy for handling
	// duplicate file names during [Zip.Load]. If nil,
	// defaults to [ActionReplace] (Last Write Wins).
	ConflictHandler ConflictHandler

	// TextDecoder handles filename decoding for legacy archives (non-UTF8).
	// This function is only used in read operations. GoZip always sets
	// the UTF-8 flag for maximum compatibility when writing.
	// Default: [DecodeCP437] (IBM PC).
	TextDecoder TextDecoder

	// OnFileDone is a callback triggered after a file is written, read, or extracted.
	// Errors are not wrapped in [FileError], because file instance is passed separately.
	// This callback can be used to stop bulk operations on the first error.
	//
	// WARNING: This callback may be triggered concurrently if [WithWorkers] is used.
	OnFileDone func(*File, error)

	// MemoryThreshold determines the maximum file size in bytes that
	// can be buffered in memory. If the file size exceeds this threshold,
	// a temporary file will be used. The default value is 10 MB.
	MemoryThreshold int64

	// IncludeImplicitDirs determines whether to include implicitly
	// created dirs in the resulting archive for saving specific metadata.
	IncludeImplicitDirs bool
}

ZipConfig defines global configuration parameters for the archive. These settings apply to the entire archive but can be overridden per-file using FileConfig options.

type ZipOption added in v1.4.0

type ZipOption func(*processConfig)

ZipOption is a function option for configuring Zip operations.

func WithExcludeDir added in v1.4.0

func WithExcludeDir(dirPath string) ZipOption

WithExcludeDir excludes a directory and its contents from operation.

func WithFilter added in v1.4.0

func WithFilter(f Filter) ZipOption

WithFilter allows using any custom Filter as an option.

func WithFromDir added in v1.4.0

func WithFromDir(dirPath string) ZipOption

WithFromDir restricts operation to files nested under the specified path.

func WithOnFileDone added in v1.4.0

func WithOnFileDone(fn func(*File, error)) ZipOption

WithOnFileDone overrides global [ZipConfig.OnFileDone]

func WithOnly added in v1.4.0

func WithOnly(files []*File) ZipOption

WithOnly filters the operation to only the specific files provided.

func WithOpPassword added in v1.4.0

func WithOpPassword(pwd string) ZipOption

WithOpPassword overwrites password for each file in the operation.

func WithProgress added in v1.4.0

func WithProgress(cb func(ProgressStats)) ZipOption

WithProgress adds a callback to monitor bytes in real time. If operation uses workers, this progress is called concurrently.

func WithSecurity added in v1.4.0

func WithSecurity(settings SecuritySettings) ZipOption

WithSecurity applies security settings for extraction.

func WithSmartStore added in v1.4.0

func WithSmartStore(exts ...string) ZipOption

WithSmartStore disables compression for files whose extensions are in the list. Passed extensions are merged with DefaultStoreExtensions. This filter changes the state of File objects in the archive.

func WithWorkers added in v1.4.0

func WithWorkers(n int) ZipOption

WithWorkers sets the given amount of workers for the operation.

type ZipStrategy added in v1.4.0

type ZipStrategy int

ZipStrategy determines the write strategy.

const (
	StrategyPerformance ZipStrategy = iota // Maximum speed, order doesn't matter
	StrategyOrdered                        // Preserve the original file order
)

Directories

Path Synopsis
sys

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL