Golang标准库——compress

  • flate
  • gzip
  • bzip2
  • lzw
  • zlib

flate

flate包实现了deflate压缩数据格式,参见RFC 1951。gzip包和zlib包实现了对基于deflate的文件格式的访问。

Constants

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

type CorruptInputError

type CorruptInputError int64

CorruptInputError表示在输入的指定偏移量位置存在损坏。

func (CorruptInputError) Error

func (e CorruptInputError) Error() string

type InternalError

type InternalError string

InternalError表示flate数据自身的错误。

func (InternalError) Error

func (e InternalError) Error() string

type ReadError

type ReadError struct {
    Offset int64 // 错误出现的位置(字节偏移量)
    Err    error // 下层的读取操作返回的错误
}

ReadError代表在读取输入流时遇到的错误。

func (*ReadError) Error

func (e *ReadError) Error() string

type WriteError

type WriteError struct {
    Offset int64 // 错误出现的位置(字节偏移量)
    Err    error // 下层的写入操作返回的错误
}

WriteError代表在写入输出流时遇到的错误。

func (*WriteError) Error

func (e *WriteError) Error() string

type Reader

type Reader interface {
    io.Reader
    io.ByteReader
}

NewReader真正需要的接口。如果提供的Io.Reader没有提供ReadByte方法,NewReader函数会自行添加缓冲。

func NewReader

func NewReader(r io.Reader) io.ReadCloser

NewReader返回一个从r读取并解压数据的io.ReadCloser。调用者有责任在读取完毕后调用返回值的Close方法。

func NewReaderDict

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

NewReaderDict类似NewReader,但会使用预设的字典初始化返回的Reader。

返回的Reader表现的好像原始未压缩的数据流以该字典起始(并已经被读取)。NewReaderDict用于读取NewWriterDict压缩的数据。

type Writer

type Writer struct {
    d    compressor
    dict []byte
}

Writer将提供给它的数据压缩后写入下层的io.Writer接口。

func NewWriter

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

NewWriter返回一个压缩水平为level的Writer。

和zlib包一样,level的范围是1(BestSpeed)到9 (BestCompression)。值越大,压缩效果越好,但也越慢;level为0表示不尝试做任何压缩,只添加必需的deflate框架;level为-1时会使用默认的压缩水平;如果level在[-1, 9]范围内,error返回值将是nil,否则将返回非nil的错误值。

func NewWriterDict

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

NewWriterDict类似NewWriter,但会使用预设的字典初始化返回的Writer。

返回的Writer表现的好像已经将原始、未压缩数据dict(压缩后未产生任何数据的)写入w了,使用w压缩的数据只能被使用同样的字典初始化生成的Reader接口解压缩。(类似加解密的初始向量/密钥)

func (*Writer) Reset

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

Reset将w重置,丢弃当前的写入状态,并将下层输出目标设为dst。效果上等价于将w设为使用dst和w的压缩水平、字典重新调用NewWriter或NewWriterDict返回的*Writer。

func (*Writer) Write

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

Write向w写入数据,最终会将压缩后的数据写入下层io.Writer接口。

func (*Writer) Flush

func (w *Writer) Flush() error

Flush将缓冲中的压缩数据刷新到下层io.Writer接口中。

本方法主要用在传输压缩数据的网络连接中,以保证远端的接收者可以获得足够的数据来重构数据报。Flush会阻塞直到所有缓冲中的数据都写入下层io.Writer接口后才返回。如果下层的io.Writetr接口返回一个错误,Flush也会返回该错误。在zlib包的术语中,Flush方法等价于Z_SYNC_FLUSH。

func (*Writer) Close

func (w *Writer) Close() error

Close刷新缓冲并关闭w。

gzip

gzip包实现了gzip格式压缩文件的读写,参见RFC 1952

Constants

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

这些常量都是拷贝自flate包,因此导入"compress/gzip"后,就不必再导入"compress/flate"了。

Variables

var (
    // 当读取的gzip数据的校验和错误时,会返回ErrChecksum
    ErrChecksum = errors.New("gzip: invalid checksum")
    // 当读取的gzip数据的头域错误时,会返回ErrHeader
    ErrHeader = errors.New("gzip: invalid header")
)

type Header

type Header struct {
    Comment string    // 注释
    Extra   []byte    // 额外数据
    ModTime time.Time // 修改时间go
    Name    string    // 文件名
    OS      byte      // 操作系统类型
}

gzip文件保存一个头域,提供关于被压缩的文件的一些元数据。该头域作为Writer和Reader类型的一个可导出字段,可以提供给调用者访问。

type Reader

type Reader struct {
    Header       // valid after NewReader or Reader.Reset
    r            flate.Reader
    decompressor io.ReadCloser
    digest       uint32 // CRC-32, IEEE polynomial (section 8)
    size         uint32 // Uncompressed size (section 2.3.1)
    buf          [512]byte
    err          error
    multistream  bool
}

Reader类型满足io.Reader接口,可以从gzip格式压缩文件读取并解压数据。

一般,一个gzip文件可以是多个gzip文件的串联,每一个都有自己的头域。从Reader读取数据会返回串联的每个文件的解压数据,但只有第一个文件的头域被记录在Reader的Header字段里。

gzip文件会保存未压缩数据的长度与校验和。当读取到未压缩数据的结尾时,如果数据的长度或者校验和不正确,Reader会返回ErrCheckSum。因此,调用者应该将Read方法返回的数据视为暂定的,直到他们在数据结尾获得了一个io.EOF。

func NewReader

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

NewReader返回一个从r读取并解压数据的*Reader。其实现会缓冲输入流的数据,并可能从r中读取比需要的更多的数据。调用者有责任在读取完毕后调用返回值的Close方法。

func (*Reader) Reset

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

Reset将z重置,丢弃当前的读取状态,并将下层读取目标设为r。效果上等价于将z设为使用r重新调用NewReader返回的Reader。这让我们可以重用z而不是再申请一个新的。(因此效率更高)

func (*Reader) Read

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

func (*Reader) Close

func (z *Reader) Close() error

调用Close会关闭z,但不会关闭下层io.Reader接口。

func main() {
   // 压缩
   tarFile := "C:/Users/Administrator/Downloads/test001/demo.tar.gz"
   dest := "C:/Users/Administrator/Downloads/test001/"

   srcFile, err := os.Open(tarFile)
   if err != nil {
      fmt.Println(err)
      return
   }
   defer srcFile.Close()
   gr, err := gzip.NewReader(srcFile)
   if err != nil {
      fmt.Println(err)
      return
   }
   defer gr.Close()
   tr := tar.NewReader(gr)
   for {
      hdr, err := tr.Next()
      if err != nil {
         if err == io.EOF {
            break
         } else {
            fmt.Println(err)
            return
         }
      }
      filename := dest + hdr.Name
      err = os.MkdirAll(string([]rune(filename)[0:strings.LastIndex(filename, "/")]), 0755)
      if err != nil {
         fmt.Println(err)
         return
      }
      file, _ := os.Create(filename)
      io.Copy(file, tr)
   }
}

解压文件 tar.gz,先解压缩gzip,再解tar包

type Writer

type Writer struct {
    Header      // written at first call to Write, Flush, or Close
    w           io.Writer
    level       int
    wroteHeader bool
    compressor  *flate.Writer
    digest      uint32 // CRC-32, IEEE polynomial (section 8)
    size        uint32 // Uncompressed size (section 2.3.1)
    closed      bool
    buf         [10]byte
    err         error
}

Writer满足io.WriteCloser接口。它会将提供给它的数据压缩后写入下层io.Writer接口。

func NewWriter

func NewWriter(w io.Writer) *Writer

NewWriter创建并返回一个Writer。写入返回值的数据都会在压缩后写入w。调用者有责任在结束写入后调用返回值的Close方法。因为写入的数据可能保存在缓冲中没有刷新入下层。

如要设定Writer.Header字段,调用者必须在第一次调用Write方法或者Close方法之前设置。Header字段的Comment和Name字段是go的utf-8字符串,但下层格式要求为NUL中止的ISO 8859-1 (Latin-1)序列。如果这两个字段的字符串包含NUL或非Latin-1字符,将导致Write方法返回错误。

func NewWriterLevel

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

NewWriterLevel类似NewWriter但指定了压缩水平而不是采用默认的DefaultCompression。

参数level可以是DefaultCompression、NoCompression或BestSpeed与BestCompression之间包括二者的任何整数。如果level合法,返回的错误值为nil。

func (*Writer) Reset

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

Reset将z重置,丢弃当前的写入状态,并将下层输出目标设为dst。效果上等价于将w设为使用dst和w的压缩水平重新调用NewWriterLevel返回的*Writer。这让我们可以重用z而不是再申请一个新的。(因此效率更高)

func (*Writer) Write

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

Write将p压缩后写入下层io.Writer接口。压缩后的数据不一定会立刻刷新,除非Writer被关闭或者显式的刷新。

func (*Writer) Flush

func (z *Writer) Flush() error

Flush将缓冲中的压缩数据刷新到下层io.Writer接口中。

本方法主要用在传输压缩数据的网络连接中,以保证远端的接收者可以获得足够的数据来重构数据报。Flush会阻塞直到所有缓冲中的数据都写入下层io.Writer接口后才返回。如果下层的io.Writetr接口返回一个错误,Flush也会返回该错误。在zlib包的术语中,Flush方法等价于Z_SYNC_FLUSH。

func (*Writer) Close

func (z *Writer) Close() error

调用Close会关闭z,但不会关闭下层io.Writer接口。

func main() {
   // 压缩
   dest := "C:/Users/Administrator/Downloads/test001/demo.tar.gz"
   d, _ := os.Create(dest)

   defer d.Close()
   gw := gzip.NewWriter(d)
   defer gw.Close()
   tw := tar.NewWriter(gw)
   defer tw.Close()
   file_dirs := []string{"C:/Users/Administrator/Downloads/test001/test01.sh", "C:/Users/Administrator/Downloads/test001/test02.sh"}

   var files []*os.File
   for _, dir := range file_dirs {
      file, _ := os.Open(dir)
      files = append(files, file)
   }

   for _, file := range files {
      info, err := file.Stat()
      if err != nil {
         fmt.Println(err)
         return
      }
      header, err := tar.FileInfoHeader(info, "")
      if err != nil {
         fmt.Println(err)
         return
      }
      err = tw.WriteHeader(header)
      if err != nil {
         fmt.Println(err)
         return
      }
      _, err = io.Copy(tw, file)
      file.Close()
      if err != nil {
         fmt.Println(err)
         return
      }
   }
}

压缩文件 tar与gzip结合,,再打tar包,再压缩

bzip2

bzip2包实现bzip2的解压缩。提供了一个对bzip2压缩包进行读取的操作,但是并没有提供进行bzip2压缩操作。

type StructuralError

type StructuralError string

当bzip2数据的语法不合法时,会返回本类型错误。

func (StructuralError) Error

func (s StructuralError) Error() string

func NewReader

func NewReader(r io.Reader) io.Reader

NewReader返回一个从r读取bzip2压缩数据并解压缩后返回给调用者的io.Reader。

func main() {
   fz, err := os.Open("test.bz2")
   if err != nil {
      log.Fatal(err)
   }
   w := bzip2.NewReader(fz)
   buf := make([]byte, 1024 * 100)
   for {
      n, err := w.Read(buf)
      if n == 0 || err != nil {
         break
      }
      fmt.Println(string(buf[:n]))
   }
}

lzw

lzw包实现了Lempel-Ziv-Welch数据压缩格式,这是一种T. A. Welch在“A Technique for High-Performance Data Compression”一文(Computer, 17(6) (June 1984), pp 8-19)提出的一种压缩格式。

本包实现了用于GIF、TIFF、PDF文件的lzw压缩格式,这是一种最长达到12位的变长码,头两个非字面码为clear和EOF码。

type Order

type Order int

Order指定一个lzw数据流的位顺序。

const (
    // LSB表示最小权重位在前,用在GIF文件格式
    LSB Order = iota
    // MSB表示最大权重位在前,用在TIFF和PDF文件格式
    MSB
)

func NewReader

func NewReader(r io.Reader, order Order, litWidth int) io.ReadCloser

创建一个io.ReadCloser,它从r读取并解压数据。调用者有责任在结束读取后调用返回值的Close方法;litWidth指定字面码的位数,必须在[2,8]范围内,一般为8。

func NewWriter

func NewWriter(w io.Writer, order Order, litWidth int) io.WriteCloser

创建一个io.WriteCloser,它将数据压缩后写入w。调用者有责任在结束写入后调用返回值的Close方法;litWidth指定字面码的位数,必须在[2,8]范围内,一般为8。

zlib

zlib包实现了对zlib格式压缩数据的读写,参见RFC 1950

本包的实现提供了在读取时解压和写入时压缩的滤镜。

Constants

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

这些常量都是拷贝自flate包,因此导入"compress/zlib"后,就不必再导入"compress/flate"了。

Variables

var (
    // 当读取的zlib数据的校验和错误时,会返回ErrChecksum
    ErrChecksum = errors.New("zlib: invalid checksum")
    // 当读取的zlib数据的目录错误时,会返回ErrDictionary
    ErrDictionary = errors.New("zlib: invalid dictionary")
    // 当读取的zlib数据的头域错误时,会返回ErrHeader
    ErrHeader = errors.New("zlib: invalid header")
)

func NewReader

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

NewReader返回一个从r读取并解压数据的io.ReadCloser。其实现会缓冲输入流的数据,并可能从r中读取比需要的更多的数据。调用者有责任在读取完毕后调用返回值的Close方法。

func NewReaderDict

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

NewReaderDict类似NewReader,但会使用预设的字典初始化返回的Reader。

如果压缩数据没有采用字典,本函数会忽略该参数。

type Writer

type Writer struct {
    w           io.Writer
    level       int
    dict        []byte
    compressor  *flate.Writer
    digest      hash.Hash32
    err         error
    scratch     [4]byte
    wroteHeader bool
}

Writer将提供给它的数据压缩后写入下层io.Writer接口。

func NewWriter

func NewWriter(w io.Writer) *Writer

NewWriter创建并返回一个Writer。写入返回值的数据都会在压缩后写入w。

调用者有责任在结束写入后调用返回值的Close方法。因为写入的数据可能保存在缓冲中没有刷新入下层。

Example

func NewWriterLevel

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

NewWriterLevel类似NewWriter但指定了压缩水平而不是采用默认的DefaultCompression。

参数level可以是DefaultCompression、NoCompression或BestSpeed与BestCompression之间包括二者的任何整数。如果level合法,返回的错误值为nil。

func NewWriterLevelDict

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

NewWriterLevelDict类似NewWriterLevel但还指定了用于压缩的字典。dict参数可以为nil;否则,在返回的Writer关闭之前,其内容不可被修改。

func (*Writer) Reset

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

Reset将w重置,丢弃当前的写入状态,并将下层输出目标设为dst。效果上等价于将w设为使用dst和w的压缩水平、字典重新调用NewWriterLevel或NewWriterLevelDict返回的*Writer。

func (*Writer) Write

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

Write将p压缩后写入下层io.Writer接口。压缩后的数据不一定会立刻刷新,除非Writer被关闭或者显式的刷新。

func (*Writer) Flush

func (z *Writer) Flush() error

Flush将缓冲中的压缩数据刷新到下层io.Writer接口中。

func (*Writer) Close

func (z *Writer) Close() error

调用Close会刷新缓冲并关闭w,但不会关闭下层io.Writer接口。

func main() {
   // 压缩
   buff := []byte{120, 156, 202, 72, 205, 201, 201, 215, 81, 40, 207,
      47, 202, 73, 225, 2, 4, 0, 0, 255, 255, 33, 231, 4, 147}
   b := bytes.NewReader(buff)
   r, err := zlib.NewReader(b)
   if err != nil {
      panic(err)
   }
   io.Copy(os.Stdout, r)
   r.Close()


   var in bytes.Buffer
   w := zlib.NewWriter(&in)
   w.Write([]byte("hello, world\n"))
   w.Close()
   zib := in.Bytes()
   fmt.Println(zib)

   bb := bytes.NewReader(zib)
   var out bytes.Buffer
   r, _ = zlib.NewReader(bb)
   io.Copy(&out, r)
   fmt.Println(out.Bytes())
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352