Working with zip archives is a common task for developers, whether it's for compressing files, creating backups, or distributing multiple files as a single package. In Go, the archive/zip package provides solid functionality to handle zip files efficiently. This article will guide you through creating and extracting zip files using this package.

Creating a Zip Archive

To create a zip archive, you'll need to initiate a new zip writer and add files to it. Below is a step-by-step guide to creating a zip file using the archive/zip package:

Step-by-Step Code Example

package main

import (
	"archive/zip"
	"fmt"
	"io"
	"log"
	"os"
)

func main() {
	// Creating a zip file
	zipFile, err := os.Create("example.zip")
	if err != nil {
		log.Fatal(err)
	}
	defer zipFile.Close()

	// Creating a zip writer
	zipWriter := zip.NewWriter(zipFile)
	defer zipWriter.Close()

	// List of files to add to the zip
	files := []string{"file1.txt", "file2.txt"}

	for _, file := range files {
		addFileToZip(zipWriter, file)
	}
}

// Function to add a file to the zip archive
func addFileToZip(zipWriter *zip.Writer, filename string) {
	fileToZip, err := os.Open(filename)
	if err != nil {
		log.Fatal(err)
	}
	defer fileToZip.Close()

	// Getting file information
	info, err := fileToZip.Stat()
	if err != nil {
		log.Fatal(err)
	}

	// Creating a zip header from the file info
	header, err := zip.FileInfoHeader(info)
	if err != nil {
		log.Fatal(err)
	}

	// Using the filename for the header name
	header.Name = filename

	// Creating a writer for the header
	writer, err := zipWriter.CreateHeader(header)
	if err != nil {
		log.Fatal(err)
	}

	// Copying the file content to the zip
	_, err = io.Copy(writer, fileToZip)
	if err != nil {
		log.Fatal(err)
	}
}

Extracting a Zip Archive

Let’s move on to extracting files from a zip archive. You’ll require reading the zip file and extracting its contents to a desired location on your filesystem. Here’s how you can accomplish this using archive/zip:

Step-by-Step Code Example

package main

import (
	"archive/zip"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
)

func main() {
	zipPath := "example.zip"
	destination := "output_folder"

	// Opening the zip file
	zipReader, err := zip.OpenReader(zipPath)
	if err != nil {
		log.Fatal(err)
	}
	defer zipReader.Close()

	// Iterating through each file in the archive
	for _, file := range zipReader.File {
		fmt.Println("Extracting", file.Name)

		// Creating the full path for the file
		filePath := filepath.Join(destination, file.Name)
		outputFile(file, filePath)
	}
}

// Function to output an individual file
func outputFile(zf *zip.File, filePath string) {
	// Creating directories if necessary
	if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
		log.Fatal(err)
	}

	// Creating the output file
	fileWriter, err := os.Create(filePath)
	if err != nil {
		log.Fatal(err)
	}
	defer fileWriter.Close()

	// Opening the zip file for reading
	src, err := zf.Open()
	if err != nil {
		log.Fatal(err)
	}
	defer src.Close()

	// Copying data from zip to the output file
	_, err = io.Copy(fileWriter, src)
	if err != nil {
		log.Fatal(err)
	}
}

Conclusion

The archive/zip package simplifies working with zip archives significantly. Creating and extracting zip files are the two most common operations that you can easily perform by following the steps and code examples discussed above. This package is very powerful and can be integrated into larger systems to help manage file organization and distribution effectively.