Golang标准库 archive/zip
提供了对zip压缩包的解析功能,主要的NewReader
方法签名为:
func NewReader(r io.ReaderAt, size int64) (*Reader, error)
需要提供一个比较特别的 io.ReaderAt
参数,另外还要提供文件大小。
基本的使用方法:
func main() {
f, err := os.Open("demo.zip")
if err != nil {
log.Fatal(err)
}
defer f.Close()
stat, err := f.Stat()
if err != nil {
log.Fatal(err)
}
r, err := zip.NewReader(f, stat.Size())
if err != nil {
log.Fatal(err)
}
for _, z := range r.File {
log.Println("file name:", z.Name)
zf, err := z.Open()
if err != nil {
continue
}
io.ReadAll(zf)
zf.Close()
}
}
这和其他类似的NewReader
方法签名有很大差别,比如说 archive/tar
,compress/bzip2
,compress/flate
,compress/gzip
,compress/zlib
等包中的 NewReader
方法基本只需要一个普通的 io.Reader
参数,如果有一个zip包也只需要 io.Reader
,则可以让这些解压缩方法保持一致性。
作为替代品,我们可以使用这个库 https://github.com/zhyee/zipiterator,提供的NewReader
方法为:
func NewReader(r io.Reader) *Reader
使用示例:
package main
import (
"io"
"log"
"os"
"github.com/zhyee/zipiterator"
)
func main() {
f, err := os.Open("demo.zip")
if err != nil {
log.Fatal(err)
}
defer f.Close()
zr := zipiterator.NewReader(f)
for {
e, err := zr.GetNextEntry()
if err == io.EOF {
break
}
if err != nil {
log.Fatalf("unable to get next entry: %s", err)
}
log.Println("entry name: ", e.Name)
log.Println("entry comment: ", e.Comment)
log.Println("entry reader version: ", e.ReaderVersion)
log.Println("entry modify time: ", e.Modified)
log.Println("entry compressed size: ", e.CompressedSize64)
log.Println("entry uncompressed size: ", e.UncompressedSize64)
log.Println("entry is a dir: ", e.IsDir())
if !e.IsDir() {
rc, err := e.Open()
if err != nil {
log.Fatalf("unable to open zip file: %s", err)
}
content, err := io.ReadAll(rc)
if err != nil {
log.Fatalf("read zip file content fail: %s", err)
}
log.Println(string(content))
if uint64(len(content)) != e.UncompressedSize64 {
log.Fatalf("read zip file length not equal with UncompressedSize64")
}
if err := rc.Close(); err != nil {
log.Fatalf("close zip entry reader fail: %s", err)
}
}
}
}
当然,该包也存在一些限制,比如只能顺序读取,不支持并发读取等等。