archive/zipパッケージなるものがあります.
The Go Programming Language - Package zip
使い方
zipアーカイブは複数のファイルが入るので, 1つのio.Writerから複数ファイルのwriterを作成する構成をとっているようです.
- zipWriter(io.Writerから作成)
- writer(zipWriterから作成)
- writer(zipWriterから作成)
- writer(zipWriterから作成)
なので手順としては
- zip.NewWriterへio.Writerを渡してzipWriterを作る
- zipWriterから各ファイルのwriterを作る
- 作った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/*