write ahead log

ロールフォワード用

golangでzipを作る

archive/zipパッケージなるものがあります.

The Go Programming Language - Package zip

使い方

zipアーカイブは複数のファイルが入るので, 1つのio.Writerから複数ファイルのwriterを作成する構成をとっているようです.

  • zipWriter(io.Writerから作成)
    • writer(zipWriterから作成)
    • writer(zipWriterから作成)
    • writer(zipWriterから作成)

なので手順としては

  1. zip.NewWriterへio.Writerを渡してzipWriterを作る
  2. zipWriterから各ファイルのwriterを作る
  3. 作ったwriterへファイルの内容を書き込む

となります.

サンプルコード

先に動作を.

こんなフォルダを.

test/
├── bar.txt
├── foo.txt
└── test.txt

こんな感じで圧縮できます.

$ ./sample.exe test.zip test/*

コードは以下の通り.

package main

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

func main() {
    if len(os.Args) < 3 {
        fmt.Println("Usage: %s [zipname] [src] [src2] ...")
        return
    }

    dest, err := os.Create(os.Args[1])
    if err != nil {
        panic(err)
    }

    zipWriter := zip.NewWriter(dest)
    defer zipWriter.Close()

    for _, s := range os.Args[2:] {
        if err := addToZip(s, zipWriter); err != nil {
            panic(err)
        }
    }
}

func addToZip(filename string, zipWriter *zip.Writer) error {
    src, err := os.Open(filename)
    if err != nil {
        return err
    }
    defer src.Close()

    writer, err := zipWriter.Create(filename)
    if err != nil {
        return err
    }

    _, err = io.Copy(writer, src)
    if err != nil {
        return err
    }

    return nil
}

感想

たった50行程度でいつも使っているzipができるというのはなかなか感慨深いものがありました.

今度はzipの構成とか調べてみようかな.

余談

io.Writer使ってるんで当たり前ですが, http経由で渡すとか, そんなのも割と簡単に書けます.

package main

import (
    "archive/zip"
    "io"
    "net/http"
    "os"
)

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}

func handler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/zip")
    w.Header().Set("Content-Disposition", "attachment; filename=test.zip")

    zipWriter := zip.NewWriter(w)
    defer zipWriter.Close()

    for _, s := range os.Args[1:] {
        if err := addToZip(s, zipWriter); err != nil {
            panic(err)
        }
    }
}

func addToZip(filename string, zipWriter *zip.Writer) error {
    src, err := os.Open(filename)
    if err != nil {
        return err
    }
    defer src.Close()

    writer, err := zipWriter.Create(filename)
    if err != nil {
        return err
    }

    _, err = io.Copy(writer, src)
    if err != nil {
        return err
    }

    return nil
}
$ ./sample.exe test/*