一、首先定义一个压缩接口,以便支持不同的压缩方式
//压缩接口,压缩类需要实现以下两个方法
type Compressor interface {
Compress(b []byte, c []byte) ([]byte, error) //压缩数据
Decompress(c []byte, b []byte) error //解压缩数据
}
//工厂类,创建不同的压缩
func NewCompressor(compressFormat string) Compressor {
compressFormat = strings.ToLower(compressFormat)
if compressFormat == "snappy" {
return NewSnappyCompressor()
} else if compressFormat == "zlib" {
return NewZlibCompressor()
} else {
return nil
}
}
//封装一个全局读取函数,止到数据全部读完或超时
func ReadAll(conn io.Reader, data []byte) error {
left:= len(data)
for left > 0 {
n, err:= conn.Read(data)
if n == left && err == nil {
return nil
}
if n > 0 {
data = data[n:]
left -= n
}
if err != nil {
return err
}
}
return nil
}
二、实现Zlib压缩
package compress
import (
"compress/zlib"
"io"
"bytes"
"io/ioutil"
"fmt"
)
//创建压缩接口工厂类
func NewZlibCompressor() Compressor {
fc:= &zlibCompressor{}
fc.reader = newZlibReader()
var err error
fc.writer, err = zlib.NewWriterLevel(ioutil.Discard, zlib.BestSpeed)
if err != nil {
panic(err)
}
return fc
}
//该类需要实现压缩接口的两个方法
type zlibCompressor struct {
writer *zlib.Writer
reader io.ReadCloser
}
func newZlibReader() (reader io.ReadCloser) {
w:= bytes.NewBuffer(nil)
cw:= zlib.NewWriter(w)
cw.Write(nil)
cw.Flush()
reader, _ = zlib.NewReader(bytes.NewReader(w.Bytes()))
return
}
//实现压缩方法
func (fc *zlibCompressor) Compress(b []byte, c []byte) ([]byte, error) {
wb:= bytes.NewBuffer(c)
fc.writer.Reset(wb)
n, err:= fc.writer.Write(b)
if err != nil {
return nil, err
}
if n!= len(b) {
return nil, fmt.Errorf("errNotFullyCompressed")
}
fc.writer.Flush()
return wb.Bytes(), nil
}
//实现解压方法
func (fc *zlibCompressor) Decompress(c []byte, b []byte) error {
fc.reader.(zlib.Resetter).Reset(bytes.NewReader(c), nil)
return ReadAll(fc.reader, b)
}
三、实现snappy压缩,该压缩速度最快,cpu占用率低,压缩比例相对更大些
package compress
import (
"github.com/golang/snappy"
"os"
"bytes"
"fmt"
)
func NewSnappyCompressor() Compressor {
return &snappyCompressor{
writer: snappy.NewWriter(os.Stdout),
reader: snappy.NewReader(os.Stdin),
}
}
type snappyCompressor struct {
writer *snappy.Writer
reader *snappy.Reader
}
func (sc *snappyCompressor) Compress(b []byte, c []byte) ([]byte, error) {
wb:= bytes.NewBuffer(c)
sc.writer.Reset(wb)
n, err:= sc.writer.Write(b)
if err != nil {
return nil, err
}
if n!= len(b) {
return nil, fmt.Errorf("errNotFullyCompressed")
}
sc.writer.Flush()
return wb.Bytes(), nil
}
func (sc *snappyCompressor) Decompress(c []byte, b []byte) error {
sc.reader.Reset(bytes.NewReader(c))
return ReadAll(sc.reader, b)
}