Working with ZIP Archives in Go (Golang)
In modern Go development, the need to work with archives often arises — for packaging logs, distributing configurations, backups, or transferring data between microservices. The Go standard library provides a powerful and flexible package archive/zip that allows you to create, read, and modify ZIP archives without third-party dependencies. In this article, we will thoroughly cover all aspects of working with ZIP archives in Go.
Overview of the archive/zip Package
The archive/zip package is part of the Go standard library and supports:
- Reading and writing ZIP archives (PKWARE format)
- Compression using Deflate and Stored (no compression) methods
- Working with files and directories inside the archive
- Support for archive and individual file comments
- Setting file attributes (date, permissions)
- Streaming processing (archives can be gigabytes in size)
Main types: zip.Writer for creating archives and zip.Reader for reading.
Creating a ZIP Archive
To create an archive, use zip.NewWriter, which accepts an io.Writer. Each file is added via Create or CreateHeader.
package main
import ( "archive/zip" "bytes" "fmt" "io" "log" "os")
func main() { // Create a buffer for the archive buf := new(bytes.Buffer) writer := zip.NewWriter(buf)
// Add a text file file1, err := writer.Create("hello.txt") if err != nil { log.Fatal(err) } _, err = file1.Write([]byte("Hello, Go ZIP!")) if err != nil { log.Fatal(err) }
// Add a file with a subdirectory file2, err := writer.Create("config/settings.json") if err != nil { log.Fatal(err) } _, err = file2.Write([]byte(`{"version": 1, "debug": true}`)) if err != nil { log.Fatal(err) }
// Must close the writer err = writer.Close() if err != nil { log.Fatal(err) }
// Save the archive to disk err = os.WriteFile("example.zip", buf.Bytes(), 0644) if err != nil { log.Fatal(err) } fmt.Println("Archive created: example.zip")}Reading and Extracting Files from an Archive
To read an archive, use zip.NewReader, which takes an io.ReaderAt and the archive size. You can read both into memory and stream.
func readArchive() { // Open the archive file reader, err := zip.OpenReader("example.zip") if err != nil { log.Fatal(err) } defer reader.Close()
// Iterate over all files in the archive for _, file := range reader.File { fmt.Printf("File: %s (size: %d bytes)", file.Name, file.UncompressedSize64)
// Open the file inside the archive rc, err := file.Open() if err != nil { log.Fatal(err) }
// Read the content content, err := io.ReadAll(rc) if err != nil { log.Fatal(err) } rc.Close()
fmt.Printf("Content: %s
", content) }}Adding Files with Metadata
Using zip.FileHeader, you can set the date, permissions, and compression method:
func addFileWithMetadata(w *zip.Writer, name, content string) error { header := &zip.FileHeader{ Name: name, Method: zip.Deflate, // Use Deflate (compression) } // Set modification time header.SetModTime(time.Now()) // Set permissions (Unix rw-r--r--) header.SetMode(0644)
f, err := w.CreateHeader(header) if err != nil { return err } _, err = f.Write([]byte(content)) return Also in library
Monitoring Rust Applications: Libraries and Tools for Performance Tracking
Reactive Programming in C++: Libraries and Practice