使用Go压缩文件-标准库compress/gzip学习 | Go主题月

5,714 阅读2分钟

前言

在之前的文章中提到在Go中可以使用zip和tar类型进行文件归档,那么当我们的业务中如果涉及到文件的压缩和解压,Go的标准库中的comporess包也提供了一系列的算法实现,本篇主要聊聊常见的gzip类型的压缩和解压。

Header

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

每一个gzip文件都有一个Header类型的结构体来保存关于该文件相关的信息。其中Reader和Writer都包含了Header类型的字段,可以直接通过点语法供调用者使用。

解压/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
}

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

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

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

func (z *Reader) Close() error
  • 使用NewReader()来创建并返回一个从io.Reader类型的参数读取的带解压输入流的Reader类型的对象的指针。
  • 使用Reset方法可以重置已经创建的Reader对象,并将下一个读取目标设置为io.Reader类型的参数r,从而达到复用的目的。在需要解压多个文件的时候避免内存分配,提高效率。
  • 调用结束后使用Close()方法回收Reader对象。

压缩/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
}

func NewWriter(w io.Writer) *Writer

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

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

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

func (z *Writer) Flush() error

func (z *Writer) Close() error
  • NewWrite()方法创建并返回一个Writer类型的对象的指针,使用默认的压缩级别DefaultCompression,需要压缩的输入流都需要传入该指针。
  • NewWriterLevel()方法可以指定压缩级别,参数level可以是DefaultCompression、NoCompression或BestSpeed与BestCompression。
  • Write()方法可能不一定会立即将压缩的输入写入到文件中,必要时使用Flush()来讲缓冲区中的数据刷入文件。

Example

func compress(file string, gzipWriter gzip.Writer) {
	readFile, err := os.Open(file)
	if err != nil {
		log.Fatal(err)
	}
	reader := bufio.NewReader(readFile)
	for {
		s, e := reader.ReadString('\n')
		if e == io.EOF {
			break
		}
		_, err := gzipWriter.Write([]byte(s))
		if err != nil {
			log.Fatal(err)
		}
	}
}

func deCompress(src, dst string) {
	gzipFile, err := os.Open(src)
	if err != nil {
		log.Fatal(err)
	}
	gzipReader, err := gzip.NewReader(gzipFile)
	if err == io.EOF {
		return
	}
	defer gzipReader.Close()

	outfileWriter, err := os.Create(dst)
	if err != nil {
		log.Fatal(err)
	}
	defer outfileWriter.Close()
	
	_, err = io.Copy(outfileWriter, gzipReader)
	if err != nil {
		log.Fatal(err)
	}
}