Пакет flate
Обзор
Пакет flate реализует формат сжатых данных DEFLATE, описанный в RFC 1951. Пакеты compress/gzip и compress/zlib реализуют доступ к форматам файлов на основе DEFLATE.
Пример (словарь)
Предустановленный словарь можно использовать для улучшения степени сжатия. Недостаток использования словаря состоит в том, что компрессор и декомпрессор должны заранее согласовать, какой словарь использовать.
Код:
// The dictionary is a string of bytes. When compressing some input data,
// the compressor will attempt to substitute substrings with matches found
// in the dictionary. As such, the dictionary should only contain substrings
// that are expected to be found in the actual data stream.
const dict = `<?xml version="1.0"?>` + `<book>` + `<data>` + `<meta name="` + `" content="`
// The data to compress should (but is not required to) contain frequent
// substrings that match those in the dictionary.
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
// Compress the data using the specially crafted dictionary.
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)
}
// The decompressor must use the same dictionary as the compressor.
// Otherwise, the input may appear as corrupted.
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()
// Substitute all of the bytes in the dictionary with a '#' to visually
// demonstrate the approximate effectiveness of using a preset dictionary.
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" content="The Go Programming Language"/# ############authors" content="Alan Donovan and Brian Kernighan"/# ############published" content="2015-10-26"/# ############isbn" content="978-0134190440"/# ######...</##### </book>
Пример (сброс)
В приложениях, критичных к производительности, 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()
// Reset the compressor and encode from some input stream.
zw.Reset(&b)
if _, err := io.CopyBuffer(zw, &r, buf); err != nil {
log.Fatal(err)
}
if err := zw.Close(); err != nil {
log.Fatal(err)
}
// Reset the decompressor and decode to some output stream.
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.
Пример (синхронизация)
DEFLATE подходит для передачи сжатых данных по сети.
Код:
var wg sync.WaitGroup
defer wg.Wait()
// Use io.Pipe to simulate a network connection.
// A real network application should take care to properly close the
// underlying connection.
rp, wp := io.Pipe()
// Start a goroutine to act as the transmitter.
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.FieldsSeq("A long time ago in a galaxy far, far away...") {
// We use a simple framing format where the first byte is the
// message length, followed the message itself.
b[0] = uint8(copy(b[1:], m))
if _, err := zw.Write(b[:1+len(m)]); err != nil {
log.Fatal(err)
}
// Flush ensures that the receiver can read all data sent so far.
if err := zw.Flush(); err != nil {
log.Fatal(err)
}
}
if err := zw.Close(); err != nil {
log.Fatal(err)
}
}()
// Start a goroutine to act as the receiver.
wg.Add(1)
go func() {
defer wg.Done()
zr := flate.NewReader(rp)
b := make([]byte, 256)
for {
// Read the message length.
// This is guaranteed to return for every corresponding
// Flush and Close on the transmitter side.
if _, err := io.ReadFull(zr, b[:1]); err != nil {
if err == io.EOF {
break // The transmitter closed the stream
}
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...
Указатель
Файлы пакета
deflate.go deflatefast.go dict_decoder.go huffman_bit_writer.go huffman_code.go inflate.go level1.go level2.go level3.go level4.go level5.go level6.go load_store.go regmask_amd64.go token.go
Константы
const (
NoCompression = 0
BestSpeed = 1
BestCompression = 9
DefaultCompression = -1
// HuffmanOnly disables Lempel-Ziv match searching and only performs Huffman
// entropy encoding. This mode is useful in compressing data that has
// already been compressed with an LZ style algorithm (e.g. Snappy or LZ4)
// that lacks an entropy encoder. Compression gains are achieved when
// certain bytes in the input stream occur more frequently than others.
//
// Note that HuffmanOnly produces a compressed output that is
// RFC 1951 compliant. That is, any valid DEFLATE decompressor will
// continue to be able to decompress this output.
HuffmanOnly = -2
) func NewReader
func NewReader(r io.Reader) io.ReadCloser
NewReader возвращает новый ReadCloser, который можно использовать для чтения несжатой версии r. Если r также не реализует io.ByteReader, декомпрессор может прочитать из r больше данных, чем необходимо. После обнаружения последнего блока в потоке DEFLATE средство чтения возвращает io.EOF. Все данные после последнего блока игнорируются.
Возвращённый NewReader интерфейс io.ReadCloser также реализует Resetter.
func NewReaderDict
func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser
NewReaderDict аналогичен NewReader, но инициализирует средство чтения предустановленным словарём. Возвращённое средство чтения работает так, как если бы поток несжатых данных начинался с указанного словаря, который уже был прочитан. NewReaderDict обычно используется для чтения данных, сжатых с помощью NewWriterDict.
Возвращённый NewReaderDict интерфейс 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 // byte offset where error occurred
Err error // error returned by underlying 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 сбрасывает ReadCloser, возвращённый NewReader или NewReaderDict, чтобы переключить его на новый базовый Reader. Это позволяет повторно использовать ReadCloser вместо выделения нового.
type Resetter interface {
// Reset discards any buffered data and resets the Resetter as if it was
// newly initialized with the given reader.
Reset(r io.Reader, dict []byte) error
} type WriteError
WriteError сообщает об ошибке, возникшей при записи выходных данных.
Устарело: больше не возвращается.
type WriteError struct {
Offset int64 // byte offset where error occurred
Err error // error returned by underlying Write
}
func (*WriteError) Error
func (e *WriteError) Error() string
type Writer
Writer принимает записываемые в него данные и записывает их сжатую форму в базовый writer (см. NewWriter).
type Writer struct {
// contains filtered or unexported fields
}
func NewWriter
func NewWriter(w io.Writer, level int) (*Writer, error)
NewWriter возвращает новый Writer, сжимающий данные с указанным уровнем. Как и в zlib, уровни варьируются от 1 (BestSpeed) до 9 (BestCompression); более высокие уровни обычно работают медленнее, но обеспечивают лучшее сжатие. Уровень 0 (NoCompression) не пытается сжимать данные, а только добавляет необходимое обрамление DEFLATE. Уровень -1 (DefaultCompression) использует уровень сжатия по умолчанию. Уровень -2 (HuffmanOnly) использует только сжатие Хаффмана, обеспечивая очень быстрое сжатие любых типов входных данных, но значительно снижая эффективность сжатия.
Если уровень находится в диапазоне [-2, 9], возвращаемая ошибка будет nil. В противном случае возвращаемая ошибка будет не nil.
Обратите внимание, что точные байты, записываемые в w, не гарантируются обещанием совместимости Go 1. Вызывающий код, в том числе тесты, не должен зависеть от точных записываемых байтов.
func NewWriterDict
func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, error)
NewWriterDict похож на NewWriter, но инициализирует новый Writer предварительно заданным словарём. Возвращённый Writer ведёт себя так, как если бы словарь был записан в него, но без создания сжатых данных. Сжатые данные, записанные в w, можно распаковать только с помощью reader, инициализированного тем же словарём (см. NewReaderDict).
Обратите внимание, что точные байты, записанные в w, не подпадают под гарантию совместимости Go 1. Вызывающим сторонам, включая тесты, не следует полагаться на точные записанные байты.
func (*Writer) Close
func (w *Writer) Close() error
Close сбрасывает буфер и закрывает writer.
func (*Writer) Flush
func (w *Writer) Flush() error
Flush записывает все ожидающие данные в нижележащий writer. Это полезно главным образом в сжатых сетевых протоколах, чтобы гарантировать, что удалённый reader получит достаточно данных для восстановления пакета. Flush не возвращает управление, пока данные не будут записаны. Вызов Flush при отсутствии ожидающих данных всё равно заставляет Writer выдать маркер синхронизации размером не менее 4 байт. Если нижележащий writer возвращает ошибку, Flush возвращает эту ошибку.
В терминологии библиотеки zlib Flush эквивалентен Z_SYNC_FLUSH.
func (*Writer) Reset 1.2
func (w *Writer) Reset(dst io.Writer)
Reset сбрасывает состояние writer и приводит его в состояние, эквивалентное результату вызова NewWriter или NewWriterDict с dst, уровнем сжатия и словарём w.
func (*Writer) Write
func (w *Writer) Write(data []byte) (n int, err error)
Write записывает данные в w, который впоследствии запишет сжатую форму этих данных в нижележащий writer.
© Google, Inc.
Licensed under the Creative Commons Attribution License 3.0.
http://golang.org/pkg/compress/flate/