使用Go归档文件-标准库archive/zip学习 | Go主题月

2,334 阅读2分钟

前言

在实际业务中,我们可以使用zip文件的形式来实现文件归档,压缩体积等操作。Go的标准库中的archive包也提供了对tar和zip格式文件的归档和解压操作。本篇先就zip格式的文件进行讲解。

定义

常量

const (
	Store   uint16 = 0 // no compression
	Deflate uint16 = 8 // DEFLATE compressed
)

zip包提供了两种压缩算法支持

store: 不压缩

Deflate:使用Deflate算法的压缩方式,其中DEFLATE是同时使用了LZ77算法与哈夫曼编码(Huffman Coding)的一个无损数据压缩算法

FileHeader

type FileHeader struct {
    // Name是文件名,它必须是相对路径,不能以设备或斜杠开始,只接受'/'作为路径分隔符
    Name string
    CreatorVersion     uint16
    ReaderVersion      uint16
    Flags              uint16
    Method             uint16
    ModifiedTime       uint16 // MS-DOS时间
    ModifiedDate       uint16 // MS-DOS日期
    CRC32              uint32
    CompressedSize64   uint64
    UncompressedSize64 uint64
    Extra              []byte
    ExternalAttrs      uint32 // 其含义依赖于CreatorVersion
    Comment            string
}
  • func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) 根据os.FileInfo类型的参数,创建并返回包含部分信息的FileHeader

  • func (h *FileHeader) FileInfo() os.FileInfo 返回一个根据FileHeader的信息生成的os.FileInfo。

  • func (h *FileHeader) ModTime() time.Time
    获取最后一次修改时间

  • func (h *FileHeader) SetModTime(t time.Time)
    设置更改时间

  • func (h *FileHeader) Mode() (mode os.FileMode)
    返回FileHeader对应文件的文件类型和权限信息

  • func (h *FileHeader) SetMode(mode os.FileMode) 设置FileHeader对应文件的文件类型和权限信息

File

type File struct {
    FileHeader
    // contains filtered or unexported fields
}
  • func (f *File) Open() (rc io.ReadCloser, err error) Open方法返回一个io.ReadCloser接口,提供读取文件内容的方法。可以同时读取多个文件。

压缩

Writer

func NewWriter(w io.Writer) *Writer  

func (w *Writer) Close() error

func (w *Writer) Create(name string) (io.Writer, error)  

func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) 
  • NewWriter创建并返回一个将zip文件写入w的*Writer
  • Create方法传入添加到zip文件中的文件名,返回一个io.Writer,用于将内容写入该文件。参数name只接受相对路径。
  • CreateHeader使用FileHeader类型创建添加zip文件中的文件,同样返回一个io.Writer,用于将内容写入该文件。

Example

func Zip(filePath string, w io.ReadWriter) error {
    f, err := ioutil.ReadDir(filePath)
    if err != nil {
        fmt.Println(err)
    }
    zipFile, _ := os.Create("test.zip")
    w := zip.NewWriter(zipFile)
    defer w.Close()
    for _, file := range f {
        fw, _ := w.Create(file.Name())
        filecontent, err := ioutil.ReadFile(filePath + file.Name())
        if err != nil {
            fmt.Println(err)
        }
        n, err := fw.Write(filecontent)
        if err != nil {
            fmt.Println(err)
        }
    }
}

解压

Reader

type Reader struct {
    r             io.ReaderAt
    File          []*File
    Comment       string
    decompressors map[uint16]Decompressor
}
type ReadCloser struct {
    Reader
    f *os.File
}

func OpenReader(name string) (*ReadCloser, error) 
func NewReader(r io.ReaderAt, size int64) (*Reader, error) 
func (rc *ReadCloser) Close() error //关闭ReadCloser
  • 通过OpenReader,传入文件名,返回一个该文件的ReadCloser类型的对象
  • NewReader返回一个从r读取数据的*Reader,r被假设其大小为size字节。

Example

func UnZip(fileName, filePath string, w io.ReadWriter) error {
    f, err := zip.OpenReader(filePath + "/" + fileName) //读取zip文件
    if err != nil {
        fmt.Println(err)
    }
    defer f.Close()
    for _, file := range f.File {
        rc, err := file.Open()
        if err != nil {
            fmt.Println(err)
        }

        f, err := os.Create(filePath + file.Name)
        if err != nil {
            fmt.Println(err)
        }
        defer f.Close()
        n, err := io.Copy(f, rc)
        if err != nil {
            fmt.Println(err)
        }
    }
}