Travailler avec les archives ZIP en Go (Golang)
Dans le développement moderne en Go, il est souvent nécessaire de travailler avec des archives — pour compresser des logs, distribuer des configurations, effectuer des sauvegardes ou transférer des données entre microservices. La bibliothèque standard de Go fournit un package puissant et flexible archive/zip, qui permet de créer, lire et modifier des archives ZIP sans dépendances externes. Dans cet article, nous allons détailler tous les aspects du travail avec les archives ZIP en Go.
Aperçu du package archive/zip
Le package archive/zip fait partie de la bibliothèque standard de Go et prend en charge :
- La lecture et l'écriture d'archives ZIP (format PKWARE)
- La compression par méthode Deflate et Stored (sans compression)
- Le travail avec des fichiers et des dossiers dans l'archive
- La prise en charge des commentaires pour l'archive et les fichiers individuels
- La définition des attributs de fichiers (date, droits d'accès)
- Le traitement en flux (les archives peuvent peser des gigaoctets)
Types principaux : zip.Writer pour créer des archives et zip.Reader pour les lire.
Création d'une archive ZIP
Pour créer une archive, on utilise zip.NewWriter, qui accepte un io.Writer. Chaque fichier est ajouté via Create ou CreateHeader.
package main
import ( "archive/zip" "bytes" "fmt" "io" "log" "os")
func main() { // Création d'un buffer pour l'archive buf := new(bytes.Buffer) writer := zip.NewWriter(buf)
// Ajout d'un fichier texte file1, err := writer.Create("hello.txt") if err != nil { log.Fatal(err) } _, err = file1.Write([]byte("Bonjour, Go ZIP !")) if err != nil { log.Fatal(err) }
// Ajout d'un fichier avec sous-dossier 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) }
// Fermeture obligatoire du writer err = writer.Close() if err != nil { log.Fatal(err) }
// Sauvegarde de l'archive sur le disque err = os.WriteFile("example.zip", buf.Bytes(), 0644) if err != nil { log.Fatal(err) } fmt.Println("Archive créée : example.zip")}Lecture et extraction de fichiers depuis une archive
Pour lire une archive, on utilise zip.NewReader, auquel on passe un io.ReaderAt et la taille de l'archive. On peut lire en mémoire ou en flux.
func readArchive() { // Ouverture du fichier d'archive reader, err := zip.OpenReader("example.zip") if err != nil { log.Fatal(err) } defer reader.Close()
// Parcours de tous les fichiers dans l'archive for _, file := range reader.File { fmt.Printf("Fichier : %s (taille : %d octets)", file.Name, file.UncompressedSize64)
// Ouverture du fichier dans l'archive rc, err := file.Open() if err != nil { log.Fatal(err) }
// Lecture du contenu content, err := io.ReadAll(rc) if err != nil { log.Fatal(err) } rc.Close()
fmt.Printf("Contenu : %s
", content) }}Ajout de fichiers avec métadonnées
Avec zip.FileHeader, on peut définir la date, les droits d'accès et la méthode de compression :
func addFileWithMetadata(w *zip.Writer, name, content string) error { header := &zip.FileHeader{ Name: name, Method: zip.Deflate, // Utilisation de Deflate (compression) } // Définition de l'heure de modification header.SetModTime(time.Now()) // Définition des droits d'accès (Unix rw-r--r--) header.SetMode(0644)
f, err := w.CreateHeader(header) if err != nil { return err } _, err = f.Write([]byte(content)) return