Working with ZIP Archives in Go (Golang): A Complete Guide
In modern Go (Golang) development, working with archives is a common task. Whether it's packaging logs, uploading files to a server, or creating backups — the standard library archive/zip provides everything needed to create, read, and modify ZIP archives without installing third-party dependencies. In this article, we'll cover the main operations with ZIP in Go with practical examples.
Key Features of the archive/zip Package
The archive/zip package is part of the Go standard library and supports:
- Creating new ZIP archives with arbitrary folder structures
- Reading the contents of existing archives
- Extracting individual files or entire archives
- Adding files to an existing archive (via copying)
- Working with file metadata (date, permissions, comments)
- Stream processing (without loading the entire archive into memory)
Creating a ZIP Archive in Go
To create an archive, use zip.NewWriter(), which accepts an io.Writer. This allows writing the archive to a file or a buffer (e.g., for sending via HTTP).
package main
import ( "archive/zip" "bytes" "fmt" "io" "log" "os")
func createZip() { // Create a buffer for the archive buf := new(bytes.Buffer) writer := zip.NewWriter(buf)
// Add a file with text file1, err := writer.Create("hello.txt") if err != nil { log.Fatal(err) } _, err = file1.Write([]byte("Hello, world! This is a file from a ZIP archive.")) if err != nil { log.Fatal(err) }
// Add a file in a subfolder file2, err := writer.Create("docs/readme.md") if err != nil { log.Fatal(err) } _, err = file2.Write([]byte("# DocumentationReadme contents.")) if err != nil { log.Fatal(err) }
// Must close the writer err = writer.Close() if err != nil { log.Fatal(err) }
// Save the archive to a file err = os.WriteFile("example.zip", buf.Bytes(), 0644) if err != nil { log.Fatal(err) } fmt.Println("Archive created: example.zip")}
func main() { createZip()}Reading and Extracting Files from ZIP
To read an archive, use zip.OpenReader() or zip.NewReader() (for in-memory data). Each file is represented by a zip.File struct.
func readZip() { reader, err := zip.OpenReader("example.zip") if err != nil { log.Fatal(err) } defer reader.Close()
for _, f := range reader.File { fmt.Printf("File: %s (size: %d bytes)", f.Name, f.UncompressedSize64)
// Open the file contents rc, err := f.Open() if err != nil { log.Fatal(err) }
// Read the contents content, err := io.ReadAll(rc) if err != nil { log.Fatal(err) } rc.Close()
fmt.Printf("Contents: %s
", content) }}Extracting All Files to Disk
Often you need to extract an archive to a specified directory. It's important to correctly create subfolders.
func extractZip(src, dest string) { reader, err := zip.OpenReader(src) if err != nil { log.Fatal(err) } defer reader.Close()
for _, f := range reader.File { // Path for extraction fpath := filepath.Join(dest, f.Name)
// Check that the path does not escape dest (security) if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) { log.Fatalf("Invalid path: %s", fpath) }
// Create folders if f.FileInfo Also in library
PDF Generation in Java: Overview of iText, Apache PDFBox, OpenPDF Libraries
JWT Tokens in C# (.NET): Complete Guide with Examples
Working with Dates in Swift: Foundation, SwiftDate, DateTools (iOS/macOS)
Markdown Processing in C# (.NET): Libraries and Tools