...

パッケージ flate

import "compress/flate"
概要
目次

概要 ▾

flate パッケージは,RFC 1951 で記述されている DEFLATE 圧縮データ形式を実装します。 gzip と zlib パッケージが DEFLATE 方式のファイル形式にアクセスするための実装です。

例 (Dictionary)

プリセット辞書を使用して圧縮率を向上させることができます。 辞書を使用することのマイナス面は, 圧縮器と解凍器が使用する辞書を前もって同じにしておかなければならないことです。

コード:

// 辞書はバイトの文字列です。
// 入力データを圧縮するとき,圧縮器は部分文字列を辞書中のマッチで置換しようとします。
// そのため,辞書には実際のデータストリームで見つかると予想される部分文字列のみを含める必要があります。
const dict = `<?xml version="1.0"?>` + `<book>` + `<data>` + `<meta name="` + `" content="`

// 圧縮するデータには,辞書の部分文字列と頻繁に一致する部分文字列があるべきです (必須ではありません) 。
const data = `<?xml version="1.0"?>
<book>
    <meta name="title" content="The Go Programming Language"/>
    <meta name="authors" content="Alan Donovan and Brian Kernighan"/>
    <meta name="published" content="2015-10-26"/>
    <meta name="isbn" content="978-0134190440"/>
    <data>...</data>
</book>
`

var b bytes.Buffer

// 特別に準備された辞書を使ってデータを圧縮します。
zw, err := flate.NewWriterDict(&b, flate.DefaultCompression, []byte(dict))
if err != nil {
    log.Fatal(err)
}
if _, err := io.Copy(zw, strings.NewReader(data)); err != nil {
    log.Fatal(err)
}
if err := zw.Close(); err != nil {
    log.Fatal(err)
}

// 解凍プログラムは,圧縮プログラムと同じ辞書を使用しなければなりません。
// そうでないと,入力が破損しているように見えます。
fmt.Println("Decompressed output using the dictionary:")
zr := flate.NewReaderDict(bytes.NewReader(b.Bytes()), []byte(dict))
if _, err := io.Copy(os.Stdout, zr); err != nil {
    log.Fatal(err)
}
if err := zr.Close(); err != nil {
    log.Fatal(err)
}

fmt.Println()

// プリセット辞書を使用したときのおおよその効果を視覚的に示すために,
// 辞書内のすべてのバイトを "#" に置き換えます。
fmt.Println("Substrings matched by the dictionary are marked with #:")
hashDict := []byte(dict)
for i := range hashDict {
    hashDict[i] = '#'
}
zr = flate.NewReaderDict(&b, hashDict)
if _, err := io.Copy(os.Stdout, zr); err != nil {
    log.Fatal(err)
}
if err := zr.Close(); err != nil {
    log.Fatal(err)
}

出力:

Decompressed output using the dictionary:
<?xml version="1.0"?>
<book>
	<meta name="title" content="The Go Programming Language"/>
	<meta name="authors" content="Alan Donovan and Brian Kernighan"/>
	<meta name="published" content="2015-10-26"/>
	<meta name="isbn" content="978-0134190440"/>
	<data>...</data>
</book>

Substrings matched by the dictionary are marked with #:
#####################
######
	############title###########The Go Programming Language"/#
	############authors###########Alan Donovan and Brian Kernighan"/#
	############published###########2015-10-26"/#
	############isbn###########978-0134190440"/#
	######...</#####
</#####

例 (Reset)

パフォーマンスが重要なアプリケーションでは, Reset を使用して現在の圧縮器または解凍器の状態を破棄し, 以前に割り当てられたメモリを利用してすばやく再初期化できます。

コード:

proverbs := []string{
    "Don't communicate by sharing memory, share memory by communicating.\n",
    "Concurrency is not parallelism.\n",
    "The bigger the interface, the weaker the abstraction.\n",
    "Documentation is for users.\n",
}

var r strings.Reader
var b bytes.Buffer
buf := make([]byte, 32<<10)

zw, err := flate.NewWriter(nil, flate.DefaultCompression)
if err != nil {
    log.Fatal(err)
}
zr := flate.NewReader(nil)

for _, s := range proverbs {
    r.Reset(s)
    b.Reset()

    // 圧縮器をリセットし,入力ストリームからエンコードします。
    zw.Reset(&b)
    if _, err := io.CopyBuffer(zw, &r, buf); err != nil {
        log.Fatal(err)
    }
    if err := zw.Close(); err != nil {
        log.Fatal(err)
    }

    // 解凍器をリセットして,出力ストリームにデコードします。
    if err := zr.(flate.Resetter).Reset(&b, nil); err != nil {
        log.Fatal(err)
    }
    if _, err := io.CopyBuffer(os.Stdout, zr, buf); err != nil {
        log.Fatal(err)
    }
    if err := zr.Close(); err != nil {
        log.Fatal(err)
    }
}

出力:

Don't communicate by sharing memory, share memory by communicating.
Concurrency is not parallelism.
The bigger the interface, the weaker the abstraction.
Documentation is for users.

例 (Synchronization)

DEFLATE は,ネットワークを介して圧縮データを送信するのに適しています。

コード:

var wg sync.WaitGroup
defer wg.Wait()

// ネットワーク接続をシミュレートするには,io.Pipe を使用します。
// 実際のネットワークアプリケーションは,
// 基盤となる接続を正しく閉じるように注意する必要があります。
rp, wp := io.Pipe()

// 送信側として機能させるためにゴルーチンを始める。
wg.Add(1)
go func() {
    defer wg.Done()

    zw, err := flate.NewWriter(wp, flate.BestSpeed)
    if err != nil {
        log.Fatal(err)
    }

    b := make([]byte, 256)
    for _, m := range strings.Fields("A long time ago in a galaxy far, far away...") {
        // 最初のバイトがメッセージ長で,
        // その後にメッセージが続く単純なフレーミングフォーマットを使います。
        b[0] = uint8(copy(b[1:], m))

        if _, err := zw.Write(b[:1+len(m)]); err != nil {
            log.Fatal(err)
        }

        // フラッシュすれば,受信側はこれまでに送信されたすべてのデータを確実に読み取ることができます。
        if err := zw.Flush(); err != nil {
            log.Fatal(err)
        }
    }

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

// 受信側として機能させるためにゴルーチンを開始します。
wg.Add(1)
go func() {
    defer wg.Done()

    zr := flate.NewReader(rp)

    b := make([]byte, 256)
    for {
        // メッセージ長を読みます。
        // これは,送信側で対応する Flush と Close ごとに戻ることが保証されています。
        if _, err := io.ReadFull(zr, b[:1]); err != nil {
            if err == io.EOF {
                break // 送信側がストリームを閉じた
            }
            log.Fatal(err)
        }

        // Read the message content.
        n := int(b[0])
        if _, err := io.ReadFull(zr, b[:n]); err != nil {
            log.Fatal(err)
        }

        fmt.Printf("Received %d bytes: %s\n", n, b[:n])
    }
    fmt.Println()

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

出力:

Received 1 bytes: A
Received 4 bytes: long
Received 4 bytes: time
Received 3 bytes: ago
Received 2 bytes: in
Received 1 bytes: a
Received 6 bytes: galaxy
Received 4 bytes: far,
Received 3 bytes: far
Received 7 bytes: away...

定数

const (
    NoCompression      = 0
    BestSpeed          = 1
    BestCompression    = 9
    DefaultCompression = -1

    // HuffmanOnly は Lempel-Ziv の一致検索を無効にし,
    // Huffman エントロピーエンコーディングのみを実行します。
    // このモードは,エントロピー符号化器がない LZ スタイルのアルゴリズム (Snappy や LZ4 など) ですでに圧縮されているデータを圧縮するのに役立ちます。
    // 入力ストリーム内の特定のバイトが他のバイトより頻繁に発生すると,圧縮率が向上します。
    //
    // HuffmanOnly は, RFC 1951 に準拠した圧縮出力を生成します。
    // つまり,有効な DEFLATE 解凍プログラムは,引き続きこの出力を解凍できます。
    HuffmanOnly = -2
)

func NewReader

func NewReader(r io.Reader) io.ReadCloser

NewReader は, r の非圧縮バージョンを読み取るために使用できる新しい ReadCloser を返します。 r が io.ByteReader も実装していない場合,解凍器は r から必要以上のデータを読み取る可能性があります。 読み終わったら ReadCloser で Close を呼び出すのは呼び出し側の責任です。

NewReader から返される ReadCloser も Resetter を実装します。

func NewReaderDict

func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser

NewReaderDict は NewReader に似ていますが,プリセット辞書でリーダーを初期化します。 返された Reader は,圧縮されていないデータストリームが, すでに読み込まれている引数の辞書 dict で開始されているかのように動作します。 NewReaderDict は通常, NewWriterDict によって圧縮されたデータを読み取るために使用されます。

NewReader から返される ReadCloser も Resetter を実装します。

type CorruptInputError

CorruptInputError は,与えられたオフセットでの不正な入力の存在を報告します。

type CorruptInputError int64

func (CorruptInputError) Error

func (e CorruptInputError) Error() string

type InternalError

InternalError は flate コード自体のエラーを報告します。

type InternalError string

func (InternalError) Error

func (e InternalError) Error() string

type ReadError

ReadError は入力の読み込み中に発生したエラーを報告します。

非推奨: もう返されません。

type ReadError struct {
    Offset int64 // エラーが発生したバイトオフセット
    Err    error // 基になる Read から返されたエラー
}

func (*ReadError) Error

func (e *ReadError) Error() string

type Reader

NewReader に必要な実際の読み込みインターフェース。 渡された io.Reader に ReadByte が含まれていない場合, NewReader は独自のバッファリングを導入します。

type Reader interface {
    io.Reader
    io.ByteReader
}

type Resetter 1.4

Resetter は, NewReader または NewReaderDict によって返された ReadCloser をリセットして,新しい内部 Reader に切り替えます。 これにより,新しいものを割り当てる代わりに ReadCloser を再利用できます。

type Resetter interface {
    // Reset はバッファされたデータを破棄し,あたかも引数の Reader で新しく初期化されたかのように Resetter をリセットします。
    Reset(r io.Reader, dict []byte) error
}

type WriteError

WriteError は,出力の書き込み中に発生したエラーを報告します。

非推奨: もう返されません。

type WriteError struct {
    Offset int64 // エラーが発生したバイトオフセット
    Err    error // 内部の Write から返されたエラー
}

func (*WriteError) Error

func (e *WriteError) Error() string

type Writer

Writer はデータを受け取り,そのデータの圧縮形式を内部の Writer に書き込みます (NewWriter を参照) 。

type Writer struct {
    // エクスポートされていないフィールドがあります
}

func NewWriter

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

NewWriter は,指定されたレベルでデータを圧縮している新しい Writer を返します。 zlib に従うと,レベルは 1 (最速) から 9 (最高圧縮率) の範囲です。 より高いレベルは通常より遅く動きますがより圧縮率が高くなります。 レベル 0 (圧縮なし) は圧縮しません。 必要な DEFLATE フレーミングが追加されるだけです。 レベル -1 (デフォルト圧縮) はデフォルトの圧縮レベルを使用します。 レベル -2 (HuffmanOnly) はハフマン圧縮のみを使用し,あらゆる種類の入力に対して非常に速い圧縮を行いますが,かなり圧縮効率を犠牲にします。

level が [-2, 9] の範囲にある場合,返されるエラーは nil になります。 そうでなければ, nil 以外のエラーが返されます。

func NewWriterDict

func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, error)

NewWriterDict は NewWriter に似ていますが,プリセット辞書 dict を使って新しい Writer を初期化します。 返された Writer は,圧縮せずに辞書が書き込まれていたかのように動作します。 w に書き込まれた圧縮データは,同じ辞書で初期化された Reader によってのみ解凍できます。

func (*Writer) Close

func (w *Writer) Close() error

Close は書き出しプログラムをフラッシュして閉じます。

func (*Writer) Flush

func (w *Writer) Flush() error

Flush (フラッシュ) は,保留中のデータを内部のライターにフラッシュします。 主に圧縮ネットワークプロトコルで,リモートリーダーにパケットを再構築するのに十分なデータがあることを確認することは役立ちます。 データが書き込まれるまでフラッシュは戻りません。 保留データがないときに Flush を呼び出すと, Writer は少なくとも 4 バイトの同期マーカーを発行します。 内部のライターがエラーを返すと, Flush はそのエラーを返します。

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

func (*Writer) Reset 1.2

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

Reset (リセット) はライターの状態を破棄します。結果,dst と w のレベルと辞書で呼び出した NewWriter または NewWriterDict の結果と同じになります。

func (*Writer) Write

func (w *Writer) Write(data []byte) (n int, err error)

Write はデータを w に書き込みます。 これにより,最終的に圧縮形式のデータがその内部のライターに書き込まれます。