// Copyright 2010 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package gzipimport ()// These constants are copied from the flate package, so that code that imports// "compress/gzip" does not also have to import "compress/flate".const (NoCompression = flate.NoCompressionBestSpeed = flate.BestSpeedBestCompression = flate.BestCompressionDefaultCompression = flate.DefaultCompressionHuffmanOnly = flate.HuffmanOnly)// A Writer is an io.WriteCloser.// Writes to a Writer are compressed and written to w.typeWriterstruct {Header// written at first call to Write, Flush, or Close w io.Writer level int wroteHeader bool closed bool buf [10]byte compressor *flate.Writer digest uint32// CRC-32, IEEE polynomial (section 8) size uint32// Uncompressed size (section 2.3.1) err error}// NewWriter returns a new [Writer].// Writes to the returned writer are compressed and written to w.//// It is the caller's responsibility to call Close on the [Writer] when done.// Writes may be buffered and not flushed until Close.//// Callers that wish to set the fields in Writer.Header must do so before// the first call to Write, Flush, or Close.func ( io.Writer) *Writer { , := NewWriterLevel(, DefaultCompression)return}// NewWriterLevel is like [NewWriter] but specifies the compression level instead// of assuming [DefaultCompression].//// The compression level can be [DefaultCompression], [NoCompression], [HuffmanOnly]// or any integer value between [BestSpeed] and [BestCompression] inclusive.// The error returned will be nil if the level is valid.func ( io.Writer, int) (*Writer, error) {if < HuffmanOnly || > BestCompression {returnnil, fmt.Errorf("gzip: invalid compression level: %d", ) } := new(Writer) .init(, )return , nil}func ( *Writer) ( io.Writer, int) { := .compressorif != nil { .Reset() } * = Writer{Header: Header{OS: 255, // unknown },w: ,level: ,compressor: , }}// Reset discards the [Writer] z's state and makes it equivalent to the// result of its original state from [NewWriter] or [NewWriterLevel], but// writing to w instead. This permits reusing a [Writer] rather than// allocating a new one.func ( *Writer) ( io.Writer) { .init(, .level)}// writeBytes writes a length-prefixed byte slice to z.w.func ( *Writer) ( []byte) error {iflen() > 0xffff {returnerrors.New("gzip.Write: Extra data is too large") }le.PutUint16(.buf[:2], uint16(len())) , := .w.Write(.buf[:2])if != nil {return } _, = .w.Write()return}// writeString writes a UTF-8 string s in GZIP's format to z.w.// GZIP (RFC 1952) specifies that strings are NUL-terminated ISO 8859-1 (Latin-1).func ( *Writer) ( string) ( error) {// GZIP stores Latin-1 strings; error if non-Latin-1; convert if non-ASCII. := falsefor , := range {if == 0 || > 0xff {returnerrors.New("gzip.Write: non-Latin-1 header string") }if > 0x7f { = true } }if { := make([]byte, 0, len())for , := range { = append(, byte()) } _, = .w.Write() } else { _, = io.WriteString(.w, ) }if != nil {return }// GZIP strings are NUL-terminated. .buf[0] = 0 _, = .w.Write(.buf[:1])return}// Write writes a compressed form of p to the underlying [io.Writer]. The// compressed bytes are not necessarily flushed until the [Writer] is closed.func ( *Writer) ( []byte) (int, error) {if .err != nil {return0, .err }varint// Write the GZIP header lazily.if !.wroteHeader { .wroteHeader = true .buf = [10]byte{0: gzipID1, 1: gzipID2, 2: gzipDeflate}if .Extra != nil { .buf[3] |= 0x04 }if .Name != "" { .buf[3] |= 0x08 }if .Comment != "" { .buf[3] |= 0x10 }if .ModTime.After(time.Unix(0, 0)) {// Section 2.3.1, the zero value for MTIME means that the // modified time is not set.le.PutUint32(.buf[4:8], uint32(.ModTime.Unix())) }if .level == BestCompression { .buf[8] = 2 } elseif .level == BestSpeed { .buf[8] = 4 } .buf[9] = .OS _, .err = .w.Write(.buf[:10])if .err != nil {return0, .err }if .Extra != nil { .err = .writeBytes(.Extra)if .err != nil {return0, .err } }if .Name != "" { .err = .writeString(.Name)if .err != nil {return0, .err } }if .Comment != "" { .err = .writeString(.Comment)if .err != nil {return0, .err } }if .compressor == nil { .compressor, _ = flate.NewWriter(.w, .level) } } .size += uint32(len()) .digest = crc32.Update(.digest, crc32.IEEETable, ) , .err = .compressor.Write()return , .err}// Flush flushes any pending compressed data to the underlying writer.//// It is useful mainly in compressed network protocols, to ensure that// a remote reader has enough data to reconstruct a packet. Flush does// not return until the data has been written. If the underlying// writer returns an error, Flush returns that error.//// In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH.func ( *Writer) () error {if .err != nil {return .err }if .closed {returnnil }if !.wroteHeader { .Write(nil)if .err != nil {return .err } } .err = .compressor.Flush()return .err}// Close closes the [Writer] by flushing any unwritten data to the underlying// [io.Writer] and writing the GZIP footer.// It does not close the underlying [io.Writer].func ( *Writer) () error {if .err != nil {return .err }if .closed {returnnil } .closed = trueif !.wroteHeader { .Write(nil)if .err != nil {return .err } } .err = .compressor.Close()if .err != nil {return .err }le.PutUint32(.buf[:4], .digest)le.PutUint32(.buf[4:8], .size) _, .err = .w.Write(.buf[:8])return .err}
The pages are generated with Goldsv0.6.9-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.