...

パッケージ gzip

import "compress/gzip"
概要
目次

概要 ▾

gzip パッケージは, RFC 1952 に記載されている gzip フォーマット圧縮ファイルの読み書きを実装します。

例 (WriterReader)

コード:

var buf bytes.Buffer
zw := gzip.NewWriter(&buf)

// ヘッダーフィールドの設定はオプションです。
zw.Name = "a-new-hope.txt"
zw.Comment = "an epic space opera by George Lucas"
zw.ModTime = time.Date(1977, time.May, 25, 0, 0, 0, 0, time.UTC)

_, err := zw.Write([]byte("A long time ago in a galaxy far, far away..."))
if err != nil {
    log.Fatal(err)
}

if err := zw.Close(); err != nil {
    log.Fatal(err)
}

zr, err := gzip.NewReader(&buf)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Name: %s\nComment: %s\nModTime: %s\n\n", zr.Name, zr.Comment, zr.ModTime.UTC())

if _, err := io.Copy(os.Stdout, zr); err != nil {
    log.Fatal(err)
}

if err := zr.Close(); err != nil {
    log.Fatal(err)
}

出力:

Name: a-new-hope.txt
Comment: an epic space opera by George Lucas
ModTime: 1977-05-25 00:00:00 +0000 UTC

A long time ago in a galaxy far, far away...

定数

これらの定数は flate パッケージからコピーされています。 そのため, "compress/gzip" をインポートするコードは "compress/flate" をインポートする必要はありません。

const (
    NoCompression      = flate.NoCompression
    BestSpeed          = flate.BestSpeed
    BestCompression    = flate.BestCompression
    DefaultCompression = flate.DefaultCompression
    HuffmanOnly        = flate.HuffmanOnly
)

変数

var (
    // ErrChecksum は,無効なチェックサムを持つ GZIP データを読み込むと返されます。
    ErrChecksum = errors.New("gzip: invalid checksum")
    // ErrHeader は,無効なヘッダを持つ GZIP データを読み込むと返されます。
    ErrHeader = errors.New("gzip: invalid header")
)

gzip ファイルは圧縮ファイルに関するメタデータを与えるヘッダを格納します。 そのヘッダは Writer と Reader 構造体のフィールドとして公開されています。

GZIP ファイル形式の制限により,文字列は UTF-8 エンコードでなければならず, Unicode コードポイント U+0001 から U+00FF のみを含めることができます。

type Header struct {
    Comment string    // コメント
    Extra   []byte    // "追加データ"
    ModTime time.Time // 変更時間
    Name    string    // ファイル名
    OS      byte      // オペレーティングシステムの種類
}

type Reader

Reader は, gzip 形式の圧縮ファイルから非圧縮データを取得するために読み取ることができる io.Reader です。

一般に, gzip ファイルは gzip ファイルを連結したものにすることができ, それぞれが独自のヘッダーを持ちます。 Reader からの読み込みは,それぞれの非圧縮データの連結を返します。 最初のヘッダーだけが Reader フィールドに記録されます。

Gzip ファイルは圧縮されていないデータの長さとチェックサムを保存します。 Read で圧縮されていないデータの終わりに達した時に予期された長さまたはチェックサムを持っていない場合, Reader は ErrChecksum を返します。 クライアントは,データの終わりを示す io.EOF を受け取るまで, Read によって返されたデータを暫定的なものとして扱う必要があります。

type Reader struct {
    Header // NewReader または Reader.Reset の後に有効
    // エクスポートされていないフィールドがあります
}

func NewReader

func NewReader(r io.Reader) (*Reader, error)

NewReader は引数のリーダーを読み込む新しい Reader を作成します。 r が io.ByteReader を実装していない場合, 解凍器は r から必要以上のデータを読み取る可能性があります。

完了したら, Reader の Close を呼び出すのは呼び出し側の責任です。

Reader.Header フィールドは,返される Reader 内で有効になります。

func (*Reader) Close

func (z *Reader) Close() error

Close は Reader を閉じます。 内部の io.Reader は閉じません。 GZIP チェックサムを検証するには,リーダーが io.EOF まで完全に消費されている必要があります。

func (*Reader) Multistream 1.4

func (z *Reader) Multistream(ok bool)

Multistream (マルチストリーム) は,リーダーがマルチストリームファイルをサポートするかどうかを制御します。

有効になっている場合 (デフォルト), Reader は入力が,個々に gzip されたデータストリームのシーケンスであり,それぞれが独自のヘッダーとトレーラーを持ち, EOF で終わることを期待します。 そのため, gzip ファイルのシーケンスの連結は,シーケンスの連結の gzip と同等に扱われます。 これは gzip リーダーの標準的な動作です。

Multistream(false) を呼び出すと,この動作は無効になります。 これは,個々の gzip データストリームを区別したり, gzip データストリームと他のデータストリームを混在させたりするファイル形式を読み取るときに便利です。 このモードでは, Reader がデータストリームの最後に達すると, Read は io.EOF を返します。 内部のリーダーは, gzip ストリームの直後に配置するためにio.ByteReaderを実装する必要があります。 次のストリームを開始するには, z.Reset(r) に続けて z.Multistream(false) を呼び出します。 次のストリームがない場合, z.Reset(r) は io.EOF を返します。

コード:

var buf bytes.Buffer
zw := gzip.NewWriter(&buf)

var files = []struct {
    name    string
    comment string
    modTime time.Time
    data    string
}{
    {"file-1.txt", "file-header-1", time.Date(2006, time.February, 1, 3, 4, 5, 0, time.UTC), "Hello Gophers - 1"},
    {"file-2.txt", "file-header-2", time.Date(2007, time.March, 2, 4, 5, 6, 1, time.UTC), "Hello Gophers - 2"},
}

for _, file := range files {
    zw.Name = file.name
    zw.Comment = file.comment
    zw.ModTime = file.modTime

    if _, err := zw.Write([]byte(file.data)); err != nil {
        log.Fatal(err)
    }

    if err := zw.Close(); err != nil {
        log.Fatal(err)
    }

    zw.Reset(&buf)
}

zr, err := gzip.NewReader(&buf)
if err != nil {
    log.Fatal(err)
}

for {
    zr.Multistream(false)
    fmt.Printf("Name: %s\nComment: %s\nModTime: %s\n\n", zr.Name, zr.Comment, zr.ModTime.UTC())

    if _, err := io.Copy(os.Stdout, zr); err != nil {
        log.Fatal(err)
    }

    fmt.Print("\n\n")

    err = zr.Reset(&buf)
    if err == io.EOF {
        break
    }
    if err != nil {
        log.Fatal(err)
    }
}

if err := zr.Close(); err != nil {
    log.Fatal(err)
}

出力:

Name: file-1.txt
Comment: file-header-1
ModTime: 2006-02-01 03:04:05 +0000 UTC

Hello Gophers - 1

Name: file-2.txt
Comment: file-header-2
ModTime: 2007-03-02 04:05:06 +0000 UTC

Hello Gophers - 2

func (*Reader) Read

func (z *Reader) Read(p []byte) (n int, err error)

Read は io.Reader を実装し,内部の Reader から非圧縮バイトを読み取ります。

func (*Reader) Reset 1.3

func (z *Reader) Reset(r io.Reader) error

Reset は Reader z の状態を破棄し, NewReader で作成した時の元の状態の結果と同等にしますが,代わりに r から読み取ります。 これにより,新しいリーダーを割り当てずに再利用することができます。

type Writer

Writer は io.WriteCloser です。 Writer への書き込みは圧縮され, w に書き込まれます。

type Writer struct {
    Header // Write , Flush , Close の最初の呼び出しで書き込まれます。
    // エクスポートされていないフィールドがあります
}

func NewWriter

func NewWriter(w io.Writer) *Writer

NewWriter は新しい Writer を返します。 返されたライターへの書き込みは圧縮され, w に書き込まれます。

完了したら Writer の Close を呼び出すのは呼び出し側の責任です。 書き込みはバッファリングされ,Close されるまでフラッシュされないことがあります。

Writer.Header のフィールドを設定する場合, Write, Flush, または Close を最初に呼び出す前に設定する必要があります。

func NewWriterLevel

func NewWriterLevel(w io.Writer, level int) (*Writer, error)

NewWriterLevel は NewWriter に似ていますが, DefaultCompression を想定せずに圧縮レベルを指定します。

圧縮レベルは, DefaultCompression, NoCompression, HuffmanOnly ,または BestSpeed と BestCompression の間の整数値です。 レベルが有効な場合,返されるエラーは nil です。

func (*Writer) Close

func (z *Writer) Close() error

Close は,書き込まれていないデータを内部の io.Writer にフラッシュし, GZIP フッターを書き込むことで Writer を閉じます。 内部の io.Writer は閉じません。

func (*Writer) Flush 1.1

func (z *Writer) Flush() error

Flush (フラッシュ) は,保留中の圧縮データを内部のライターにフラッシュします。

リモートリーダーがパケットを再構築するのに十分なデータがあることを確認することは,主に圧縮ネットワークプロトコルで役立ちます。 データが書き込まれるまでフラッシュは戻りません。 内部のライターがエラーを返すと, Flush はそのエラーを返します。

zlib ライブラリの用語では, Flush は Z_SYNC_FLUSH と同じです。

func (*Writer) Reset 1.2

func (z *Writer) Reset(w io.Writer)

Reset (リセット) は Writer z の状態を破棄し, NewWriter または NewWriterLevel で作成されたときの元の状態のと同じにしますが,代わりに w に書き込むようにします。 これにより,新しいライターを割り当てるのではなく,ライターを再利用することができます。

func (*Writer) Write

func (z *Writer) Write(p []byte) (int, error)

Write は,内部の io.Writer に圧縮形式の p を書き込みます。 Writer が閉じられるまで,圧縮されたバイトは必ずしもフラッシュされません。