https://blog.csdn.net/m0_38132420/article/details/78711975

前言
曾经,因为不够注重基础吃了好多亏。总是很喜欢去看那些高大上的东西,却忽略了最基本的东西。然后会错误的以为自己懂的很多,但是其实是沙堆中筑高台,知道很多高大上的架构,但是基础的东西却不太了解。我觉得,可能这就是大部分开发工程师的通病吧。

正题
在软件很多应用开发过程中,经常需要使用到文件压缩。有时候是为了加快存盘速度,有时候是为了节省硬盘空间,有时候是为了提高传输效率。gzip是一种比较通用的压缩程序,golang系统自带的包里边compress/gzip就可以实现在代码中实现gzip的功能。

一、compress/gzip包的用法
先看看compress/gzip包中的测试用例

func Example_writerReader() {
    var buf bytes.Buffer
    zw := gzip.NewWriter(&buf)

    // Setting the Header fields is optional.
    zw.Name = "a-new-hope.txt"
    zw.Comment = "an epic space opera by George Lucas"
    zw.ModTime = time.Date(1977, time.May, 25, 0, 0, 0, 0, time.UTC)

    _, err := zw.Write([]byte("A long time ago in a galaxy far, far away..."))
    if err != nil {
        log.Fatal(err)
    }

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

    zr, err := gzip.NewReader(&buf)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Name: %s\nComment: %s\nModTime: %s\n\n", zr.Name, zr.Comment, zr.ModTime.UTC())

    if _, err := io.Copy(os.Stdout, zr); err != nil {
        log.Fatal(err)
    }

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

    // Output:
    // Name: a-new-hope.txt
    // Comment: an epic space opera by George Lucas
    // ModTime: 1977-05-25 00:00:00 +0000 UTC
    //
    // A long time ago in a galaxy far, far away...
}


方法说明: 

1、func NewWriter(w io.Writer) Writer
NewWriter返回一个Writer接口,调用Writer的write方法把数据压缩后写入w。并由调用者负责关闭接口,有另外一个创建Writer的接口func NewWriterLevel(w io.Writer, level int) (
Writer, error) 其使用方法和NewWriter一样,就是增加了一个压缩级别。压缩级别和gzipgzip的压缩级别定义一致。具体可以看每天回顾linux命令(gzip) 中对压缩效率的介绍。
2、func NewReader(r io.Reader) (*Reader, error)
NewReader创建一个新的Reader接口,并且将Reader的内容赋值为r,压缩数据存储在r中,并由调用者负责关闭接口。

Writer接口方法介绍
1、func (z *Writer) Close() error
关闭Writer接口,但是不关闭创建接口是引入的io.Writer。
2、func (z *Writer) Flush() error
把缓存中的数据刷到初始化时候传入的io.Writer中。注意,这个操作是个阻塞操作。
3、func (z *Writer) Reset(w io.Writer)
刷新Writer的状态为初始状态,并更替其内部的io.Writer
4、func (z *Writer) Write(p []byte) (int, error)
把p的内容压缩后写入接口实例内部的io.Writer中。支持多次写入,后面写入的拼接在先写入的后面。

Reader接口方法介绍
1、func (z *Reader) Close() error
关闭Reader接口,但是不关闭创建接口是引入的io.Reader。
2、func (z *Reader) Multistream(ok bool)
设置Reader接口是否支持多流。
3、func (z *Reader) Read(p []byte) (n int, err error)
将io.Reader内容部分的内容解压后复制到p。
4、func (z *Reader) Reset(r io.Reader) error
刷新Reader的状态为初始状态,并更替其内部的io.Reader

文件压缩实例
定义解压缩文件接口CompressFile和DeCompressFile:
gziptest.go:

package gziptest

import (
    "compress/gzip"
    "io"
    "os"
)

//压缩文件Src到Dst
func CompressFile(Dst string, Src string) error {
    newfile, err := os.Create(Dst)
    if err != nil {
        return err
    }
    defer newfile.Close()

    file, err := os.Open(Src)
    if err != nil {
        return err
    }

    zw := gzip.NewWriter(newfile)

    filestat, err := file.Stat()
    if err != nil {
        return nil
    }

    zw.Name = filestat.Name()
    zw.ModTime = filestat.ModTime()
    _, err = io.Copy(zw, file)
    if err != nil {
        return nil
    }

    zw.Flush()
    if err := zw.Close(); err != nil {
        return nil
    }
    return nil
}

//解压文件Src到Dst
func DeCompressFile(Dst string, Src string) error {
    file, err := os.Open(Src)
    if err != nil {
        panic(err)
    }
    defer file.Close()

    newfile, err := os.Create(Dst)
    if err != nil {
        panic(err)
    }
    defer newfile.Close()

    zr, err := gzip.NewReader(file)
    if err != nil {
        panic(err)
    }

    filestat, err := file.Stat()
    if err != nil {
        panic(err)
    }

    zr.Name = filestat.Name()
    zr.ModTime = filestat.ModTime()
    _, err = io.Copy(newfile, zr)
    if err != nil {
        panic(err)
    }

    if err := zr.Close(); err != nil {
        panic(err)
    }
    return nil
}

单元测试用例:
gziptest_test.go

package gziptest

import (
    "os"
    "testing"
)

func TestCompressFile(t *testing.T) {
    pwd, _ := os.Getwd()
    newfile, err := os.Create(pwd + "/test.txt")
    if err != nil {
        t.Fatal(err)
    }
    newfile.Write([]byte("hello world!!!!"))
    newfile.Close()

    err = CompressFile(pwd+"/test.gz", pwd+"/test.txt")
    if err != nil {
        t.Fatal(err)
    }
}

func TestDeCompressFile(t *testing.T) {
    pwd, _ := os.Getwd()

    err := DeCompressFile(pwd+"/test2.txt", pwd+"/test.gz")
    if err != nil {
        t.Fatal(err)
    }
}

测试结果:

C:/Go/bin/go.exe test -v [D:/go/src/gziptest]
=== RUN   TestCompressFile
--- PASS: TestCompressFile (0.00s)
=== RUN   TestDeCompressFile
--- PASS: TestDeCompressFile (0.00s)
PASS
ok      gziptest    2.351s

同级目录下增加了三个文件:
其中test.txt和test2.txt内容为:

hello world!!!!

test.gz内容为text.txt

文档更新时间: 2019-06-14 10:30   作者:月影鹏鹏