美文网首页
Golang标准库——archive

Golang标准库——archive

作者: DevilRoshan | 来源:发表于2020-09-13 23:45 被阅读0次
  • tar
  • zip

tar

tar包实现了tar格式压缩文件的存取。本包覆盖大多数文件的变种,包括GUN和BSD生成的tar文件。

Constants

const (
    // 类型
    TypeReg           = '0'    // 普通文件
    TypeRegA          = '\x00' // 普通文件
    TypeLink          = '1'    // 硬链接
    TypeSymlink       = '2'    // 符号链接
    TypeChar          = '3'    // 字符设备节点
    TypeBlock         = '4'    // 块设备节点
    TypeDir           = '5'    // 目录
    TypeFifo          = '6'    // 先进先出队列节点
    TypeCont          = '7'    // 保留位
    TypeXHeader       = 'x'    // 扩展头
    TypeXGlobalHeader = 'g'    // 全局扩展头
    TypeGNULongName   = 'L'    // 下一个文件记录有个长名字
    TypeGNULongLink   = 'K'    // 下一个文件记录指向一个具有长名字的文件
    TypeGNUSparse     = 'S'    // 稀疏文件
)

Variables

var (
    ErrWriteTooLong    = errors.New("archive/tar: write too long") //写入数据太长
    ErrFieldTooLong    = errors.New("archive/tar: header field too long") //头部太长
    ErrWriteAfterClose = errors.New("archive/tar: write after close") //关闭后写入
)

var (
    ErrHeader = errors.New("archive/tar: invalid tar header")   //无效tar 头部
)

type Header

该结构体代表了一个tar归档的头部,一些字段可能不被填充,Header中主要包含文件相关信息。

type Header struct {
    Name       string    // 文件名称
    Mode       int64     // 文件的权限和模式位
    Uid        int       // 文件所有者的用户 ID
    Gid        int       // 文件所有者的组 ID
    Size       int64     // 文件的字节长度
    ModTime    time.Time // 文件的修改时间
    Typeflag   byte      // 文件的类型
    Linkname   string    // 链接文件的目标名称
    Uname      string    // 文件所有者的用户名
    Gname      string    // 文件所有者的组名
    Devmajor   int64     // 字符设备或块设备的主设备号
    Devminor   int64     // 字符设备或块设备的次设备号
    AccessTime time.Time // 文件的访问时间
    ChangeTime time.Time // 文件的状态更改时间
}

FileInfoHeader方法

func FileInfoHeader(fi os.FileInfo, link string) (*Header, error)

FileInfoHeader返回一个根据fi填写了部分字段的Header。 如果fi描述一个符号链接,FileInfoHeader函数将link参数作为链接目标。如果fi描述一个目录,会在名字后面添加斜杠。因为os.FileInfo接口的Name方法只返回它描述的文件的无路径名,有可能需要将返回值的Name字段修改为文件的完整路径名。

FileInfo方法

func (h *Header) FileInfo() os.FileInfo

FileInfo返回该Header对应的文件信息。(os.FileInfo类型)

import (
    "archive/tar"
    "fmt"
    "os"
)

func main() {
    fileinfo, err := os.Stat("C:/Users/Administrator/Desktop/test.docx")
    if err != nil {
        fmt.Println(err)
    }
    h, err := tar.FileInfoHeader(fileinfo, "")
    h.Linkname = "linkname"
    h.Gname = "gname"
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(h.AccessTime, h.ChangeTime, h.Devmajor, h.Devminor, h.Gid, h.Gname, h.Linkname, h.ModTime, h.Mode, h.Name, h.Size, h.Typeflag, h.Uid, h.Uname, h.Xattrs)
    
    // FileInfo
    fileinfo2 := h.FileInfo()
    fmt.Println(fileinfo2.Name())
}

type Reader

type Reader struct {
    r       io.Reader
    err     error
    pad     int64           //当前文件实体之后填充的
    curr    numBytesReader  //当前文件实体的reader
    hdrBuff [blockSize]byte // 读header中使用的buffer缓存
}

Reader提供了对一个tar档案文件的顺序读取。一个tar档案文件包含一系列文件。Next方法返回档案中的下一个文件(包括第一个),返回值可以被视为io.Reader来获取文件的数据。

NewReader方法

func NewReader(r io.Reader) *Reader

NewReader创建一个从r读取的Reader。

Next方法

func (tr *Reader) Next() (*Header, error)

转入tar档案文件下一记录,它会返回下一记录的头域。

Read方法

func (tr *Reader) Read(b []byte) (n int, err error)

从档案文件的当前记录读取数据,到达记录末端时返回(0, EOF),直到调用Next方法转入下一记录。

解压缩包的方法,从 .tar 文件中读出数据是通过 tar.Reader 完成的,所以首先要创建 tar.Reader,可以通过 tar.NewReader 方法来创建它,该方法要求提供一个 os.Reader 对象,以便从该对象中读出数据。可以先打开一个 .tar 文件,然后将该文件提供给 tar.NewReader 使用。这样就可以将 .tar 文件中的数据读出来了

func main() {

    f, err := os.Open("C:/Users/Administrator/Downloads/test.tar")
    if err != nil {
        fmt.Println(err)
        return
    }
    defer f.Close()
    // NewReader
    r := tar.NewReader(f)
    // Next
    for hdr, err := r.Next(); err != io.EOF; hdr, err = r.Next() {
        if err != nil {
            fmt.Println(err)
            return
        }
        fileinfo := hdr.FileInfo()
        fmt.Println(fileinfo.Name())
        f, err := os.Create("C:/Users/Administrator/Downloads/" + fileinfo.Name())
        if err != nil {
            fmt.Println(err)
        }
        defer f.Close()
        _, err = io.Copy(f, r)
        if err != nil {
            fmt.Println(err)
        }
    }
}

type Writer

type Writer struct {
    w    io.Writer
    pad  int64      // 当前文件输入后要写入的填充量
    curr fileWriter // 当前文件条目
    hdr  Header     // Header浅拷贝
    blk  block      // 用作临时本地存储的缓冲区

    // err is a persistent error.
    // It is only the responsibility of every exported method of Writer to
    // ensure that this error is sticky.
    err error
}

Writer类型提供了POSIX.1格式的tar档案文件的顺序写入。一个tar档案文件包含一系列文件。调用WriteHeader来写入一个新的文件,然后调用Write写入文件的数据,该记录写入的数据不能超过hdr.Size字节。

NewWriter方法

func NewWriter(w io.Writer) *Writer

NewWriter创建一个写入w的*Writer。

WriterHeader方法
func (tw *Writer) WriteHeader(hdr *Header) error

WriteHeader写入hdr并准备接受文件内容。如果不是第一次调用本方法,会调用Flush。在Close之后调用本方法会返回ErrWriteAfterClose。

Writer方法

func (tw *Writer) Write(b []byte) (n int, err error)

Write向tar档案文件的当前记录中写入数据。如果写入的数据总数超出上一次调用WriteHeader的参数hdr.Size字节,返回ErrWriteTooLong错误。

Flush方法

func (tw *Writer) Flush() error

Flush结束当前文件的写入。(可选的)

Close方法

func (tw *Writer) Close() error

Close关闭tar档案文件,会将缓冲中未写入下层的io.Writer接口的数据刷新到下层。

func main() {
    f, err := os.Create("C:/Users/Administrator/Downloads/test10.tar")  //创建一个tar文件
    if err != nil {
        fmt.Println(err)
        return
    }
    defer f.Close()

    // NewWriter
    tw := tar.NewWriter(f)
    defer tw.Close()

    fileinfo, err := os.Stat("C:/Users/Administrator/Downloads/test01.sh")  //获取文件相关信息
    if err != nil {
        fmt.Println(err)
    }
    hdr, err := tar.FileInfoHeader(fileinfo, "")
    if err != nil {
        fmt.Println(err)
    }

    // WriterHeader
    err = tw.WriteHeader(hdr)    //写入头文件信息
    if err != nil {
        fmt.Println(err)
        // return
    }


    f1, err := os.Open("C:/Users/Administrator/Downloads/test01.sh")
    if err != nil {
        fmt.Println(err)
        return
    }
    m, err := io.Copy(tw, f1)   //将文件test01.sh中信息写入压缩包中
    if err != nil {
        fmt.Println(err)
        // return
    }

    fileinfo2, err := os.Stat("C:/Users/Administrator/Downloads/test02.sh")  //获取文件相关信息
    if err != nil {
        fmt.Println(err)
    }
    hdr2, err := tar.FileInfoHeader(fileinfo2, "")
    if err != nil {
        fmt.Println(err)
    }

    // WriterHeader
    err = tw.WriteHeader(hdr2)    //写入头文件信息
    if err != nil {
        fmt.Println(err)
        // return
    }


    f2, err := os.Open("C:/Users/Administrator/Downloads/test02.sh")
    if err != nil {
        fmt.Println(err)
        return
    }
    m2, err := io.Copy(tw, f2)   //将文件test02.sh中信息写入压缩包中
    if err != nil {
        fmt.Println(err)
        // return
    }

    fmt.Println(m)
    fmt.Println(m2)
}

zip

zip包提供了zip档案文件的读写服务。

本包不支持跨硬盘的压缩。

Constants

const (
    Store   uint16 = 0 // 不压缩
    Deflate uint16 = 8 // deflate 压缩
)

预定义压缩算法

Variables

var (
    ErrFormat    = errors.New("zip: not a valid zip file")    // 非正经的zip文件
    ErrAlgorithm = errors.New("zip: unsupported compression algorithm")     // 非正经的压缩算法
    ErrChecksum  = errors.New("zip: checksum error")  // 校验错误
)

type Compressor

type Compressor func(io.Writer) (io.WriteCloser, error)

Compressor函数类型会返回一个io.WriteCloser,该接口会将数据压缩后写入提供的接口。关闭时,应将缓冲中的数据刷新到下层接口中。

type Decompressor

type Decompressor func(io.Reader) io.ReadCloser

Decompressor函数类型会返回一个io.ReadCloser, 该接口的Read方法会将读取自提供的接口的数据提前解压缩。程序员有责任在读取结束时关闭该io.ReadCloser。

func RegisterCompressor

func RegisterCompressor(method uint16, comp Compressor)

RegisterCompressor使用指定的方法ID注册一个Compressor类型函数。常用的方法Store和Deflate是内建的。

func RegisterDecompressor

func RegisterDecompressor(method uint16, d Decompressor)

RegisterDecompressor使用指定的方法ID注册一个Decompressor类型函数。

type 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
   CompressedSize     uint32 // 已弃用;请使用CompressedSize64
   UncompressedSize   uint32 // 已弃用;请使用UncompressedSize64
   CompressedSize64   uint64
   UncompressedSize64 uint64
   Extra              []byte
   ExternalAttrs      uint32 // 其含义依赖于CreatorVersion
   Comment            string
}

FileHeader描述zip文件中的一个文件。参见zip的定义获取细节。

FileInfoHeader方法
func FileInfoHeader(fi os.FileInfo) (*FileHeader, error)

FileInfoHeader返回一个根据fi填写了部分字段的Header。因为os.FileInfo接口的Name方法只返回它描述的文件的无路径名,有可能需要将返回值的Name字段修改为文件的完整路径名。

FileInfo方法
func (h *FileHeader) FileInfo() os.FileInfo

FileInfo返回该Header对应的文件信息。(os.FileInfo类型)

Mode方法
func (h *FileHeader) Mode() (mode os.FileMode)

Mode返回h的权限和模式位。

SetMode方法
func (h *FileHeader) SetMode(mode os.FileMode)

SetMode修改h的权限和模式位。

ModTime方法
func (h *FileHeader) ModTime() time.Time

返回最近一次修改的UTC时间。(精度2s)

Use Modified instead.

SetModTime方法
func (h *FileHeader) SetModTime(t time.Time)

将ModifiedTime和ModifiedDate字段设置为给定的UTC时间。(精度2s)

Use Modified instead.

import (
    "archive/zip"
    "fmt"
    "os"
)

func main() {
    fileinfo, err := os.Stat("C:/Users/Administrator/Desktop/test.docx")
    if err != nil {
        fmt.Println(err)
    }
    h, err := zip.FileInfoHeader(fileinfo)
    
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(h.Name, h.Comment, h.CreatorVersion)

    // FileInfo
    fileinfo2 := h.FileInfo()
    fmt.Println(fileinfo2.Name())
    
    // Mode
    fmt.Println(h.Mode())
    // SetMode
    h.SetMode(755)
    fmt.Println(h.Mode())

    // Deprecated: Use Modified instead.
    //modTime := h.ModTime()
    //fmt.Println(modTime)
    //
    // Deprecated: Use Modified instead.
    //h.SetModTime(time.Now())
    //fmt.Println(h.ModTime())

    fmt.Println(h.Modified)
    h.Modified = time.Now()
    fmt.Println(h.Modified)
}

type File

type File struct {
   FileHeader
   zip          *Reader
   zipr         io.ReaderAt
   zipsize      int64
   headerOffset int64
}
DataOffset方法
func (f *File) DataOffset() (offset int64, err error)

DataOffset返回文件的可能存在的压缩数据相对于zip文件起始的偏移量。大多数调用者应使用Open代替,该方法会主动解压缩数据并验证校验和。

Open方法
func (f *File) Open() (rc io.ReadCloser, err error)

Open方法返回一个io.ReadCloser接口,提供读取文件内容的方法。可以同时读取多个文件。

type Reader

type Reader struct {
    r             io.ReaderAt
    File          []*File
    Comment       string
    decompressors map[uint16]Decompressor
}
NewReader方法
func NewReader(r io.ReaderAt, size int64) (*Reader, error)

NewReader返回一个从r读取数据的*Reader,r被假设其大小为size字节

type ReadCloser

type ReadCloser struct {
   f *os.File
   Reader
}
OpenReader方法
func OpenReader(name string) (*ReadCloser, error)

OpenReader会打开name指定的zip文件并返回一个*ReadCloser。

Close方法
func (rc *ReadCloser) Close() error

Close关闭zip文件,使它不能用于I/O。

func main() {
   const File = "C:/Users/Administrator/Downloads/test001.zip"
   const dir = "C:/Users/Administrator/Downloads/test001/"
   os.Mkdir(dir, 0777) //创建一个目录

   or, err := zip.OpenReader(File) //读取zip文件
   if err != nil {
      fmt.Println(err)
   }
   defer or.Close()
   for _, file := range or.File {
      rc, err := file.Open()
      if err != nil {
         fmt.Println(err)
      }

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

type Writer

// Writer implements a zip file writer.
type Writer struct {
    cw          *countWriter
    dir         []*header
    last        *fileWriter
    closed      bool
    compressors map[uint16]Compressor
    comment     string

    // testHookCloseSizeOffset if non-nil is called with the size
    // of offset of the central directory at Close.
    testHookCloseSizeOffset func(size, offset uint64)
}
NewWriter方法
func NewWriter(w io.Writer) *Writer

NewWriter创建并返回一个将zip文件写入w的*Writer。

CreateHeader方法
func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error)

使用给出的*FileHeader来作为文件的元数据添加一个文件进zip文件。本方法返回一个io.Writer接口(用于写入新添加文件的内容)。新增文件的内容必须在下一次调用CreateHeader、Create或Close方法之前全部写入。

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

使用给出的文件名添加一个文件进zip文件。本方法返回一个io.Writer接口(用于写入新添加文件的内容)。文件名必须是相对路径,不能以设备或斜杠开始,只接受'/'作为路径分隔。新增文件的内容必须在下一次调用CreateHeader、Create或Close方法之前全部写入。

Close方法
func (w *Writer) Close() error

Close方法通过写入中央目录关闭该*Writer。本方法不会也没办法关闭下层的io.Writer接口。

func main() {

    const dir =  "C:/Users/Administrator/Downloads/test001/"
    //获取源文件列表
    f, err := ioutil.ReadDir(dir)
    if err != nil {
        fmt.Println(err)
    }
    fzip, _ := os.Create("C:/Users/Administrator/Downloads/test001/test00001.zip")
    w := zip.NewWriter(fzip)
    defer w.Close()
    for _, file := range f {
        fw, _ := w.Create(file.Name())
        filecontent, err := ioutil.ReadFile(dir + file.Name())
        if err != nil {
            fmt.Println(err)
        }
        n, err := fw.Write(filecontent)
        if err != nil {
            fmt.Println(err)
        }
        fmt.Println(n)
    }
}

相关文章

网友评论

      本文标题:Golang标准库——archive

      本文链接:https://www.haomeiwen.com/subject/yqhaektx.html