• Go标准库之Zip


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

    关于ZIP64:
    为了向下兼容,FileHeader同时拥有32位和64位的Size字段。64位字段总是包含正确的值,对普通格式的档案未见它们的值是相同的。对zip64格式的档案文件32位字段将是0xffffffff,必须使用64位字段。

    // Constants
    const (
      Store   uint16 = 0
      Deflate uint16 = 8
    )
    
    // Struct
        // Header
    type File struct {
      FileHeader
    }
            // Function
                func (f *File) DataOffset() (offset int64, err error)
                // DataOffset返回文件的可能存在的压缩数据相对于 zip 文件起始的偏移量。大多数调用者应使用 Open 代替,该方法会主动解压缩数据并验证校验和。
                func (f *File) Open() (rc io.ReadCloser, err error)
                // Open方法返回一个 io.ReadCloser 接口,提供读取文件内容的方法。可以同时读取多个文件。
    
        // FileHeader
    type FileHeader struct {
      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
    }
    
            // Function
                func (h *FileHeader) FileInfo() os.FileInfo
                // FileInfo返回一个根据h的信息生成的 os.FileInfo
                func (h *FileHeader) ModTime() time.Time
                // 返回最近一次修改的UTC时间。(精度2s)
                func (h *FileHeader) Mode() (mode os.FileMode)
                // Mode返回h的权限和模式位
                func (h *FileHeader) SetModTime(t time.Time)
                // 将ModifiedTime和ModifiedDate字段设置为给定的UTC时间。(精度2s)
                func (h *FileHeader) SetMode(mode os.FileMode)
                // SetMode修改h的权限和模式位。
    
        // ReadCloser
    type ReadCloser struct {
      Reader
    }    
            // Function
                func (rc *ReadCloser) Close() error
                // Close关闭 zip 文件,使它不能用于I/O。
        
        // Reader
    type Reader struct {
    	r             io.ReaderAt
    	File          []*File
    	Comment       string
    	decompressors map[uint16]Decompressor
    }
    
        // Writer
        // Writer类型实现了 zip 文件的写入器。
    // 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)
    }
    
            // Function
                func (w *Writer) Close() error
                // Close方法通过写入中央目录关闭该* Writer 。本方法不会也没办法关闭下层的 io.Writer 接口。
                func (w *Writer) Create(name string) (io.Writer, error)
                // 使用给出的文件名添加一个文件进 zip 文件。本方法返回一个 io.Writer 接口(用于写入新添加文件的内容)。文件名必须是相对路径,不能以设备或斜杠开始,只接受’/'作为路径分隔。新增文件的内容必须在下一次调用 CreateHeader 、Create或 Close 方法之前全部写入
                func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error)
                // 使用给出的*FileHeader来作为文件的元数据添加一个文件进 zip 文件。本方法返回一个 io.Writer 接口(用于写入新添加文件的内容)。新增文件的内容必须在下一次调用CreateHeader、 Create 或 Close 方法之前全部写入。
    
        
        // Type
            type Compressor func(io.Writer) (io.WriteCloser, error)
            // Compressor函数类型会返回一个 io.WriteCloser ,该接口会将数据压缩后写入提供的接口。关闭时,应将缓冲中的数据刷新到下层接口中。
            type Decompressor func(io.Reader) io.ReadCloser
            // Decompressor函数类型会返回一个 io.ReadCloser ,该接口的Read方法会将读取自提供的接口的数据提前解压缩。程序员有责任在读取结束时关闭该 io.ReadCloser 。
    
        // Function
            func FileInfoHeader(fi os.FileInfo) (*FileHeader, error)
            // FileInfoHeader返回一个根据fi填写了部分字段的Header。因为 os.FileInfo 接口的Name方法只返回它描述的文件的无路径名,有可能需要将返回值的Name字段修改为文件的完整路径名。
            func NewReader(r io.ReaderAt, size int64) (*Reader, error)
            // NewReader返回一个从r读取数据的*Reader,r被假设其大小为size字节。
            func NewWriter(w io.Writer) *Writer
            // NewWriter创建并返回一个将 zip 文件写入w的*Writer
            func OpenReader(name string) (*ReadCloser, error)
            // OpenReader会打开name指定的 zip 文件并返回一个*ReadCloser
            func RegisterCompressor(method uint16, comp Compressor)
            // RegisterCompressor使用指定的方法ID注册一个Compressor类型函数。常用的方法Store和Deflate是内建的
            func RegisterDecompressor(method uint16, d Decompressor)
            // RegisterDecompressor使用指定的方法ID注册一个Decompressor类型函数。
    
    

    Demo

    
    //压缩Demo
    func zipFunc() {
    	zipTarget := "./zipFile.zip"
    	fileFolder := "./fileFolder"
    	zipfile, err := os.Create(zipTarget)
    	if err != nil {
    		// if file is exist then delete file
    		if err == os.ErrExist {
    			if err := os.Remove(zipTarget); err != nil {
    				fmt.Println(err)
    			}
    		} else {
    			fmt.Println(err)
    		}
    	}
    	defer zipfile.Close()
    	zipwriter := zip.NewWriter(zipfile)
    	defer zipwriter.Close()
    	sfileInfo, err := os.Stat(fileFolder)
    	if err != nil {
    		fmt.Println(err)
    	}
    	if !sfileInfo.IsDir() {
    		zipFile(fileFolder, zipwriter)
    	} else {
    		zipFolder(fileFolder, zipwriter)
    	}
    }
    
    // 压缩文件
    func zipFolder(directory string, zw *zip.Writer) error {
    	return filepath.Walk(directory, func(zipPath string, file os.FileInfo, err error) error {
    		//read the file failure
    		if file == nil {
    			return err
    		}
    		if file.IsDir() {
    			if directory == zipPath {
    				return nil
    			}
    			fileFolder := filepath.Join(directory, strings.TrimPrefix(zipPath, directory))
    			os.Mkdir(strings.TrimPrefix(directory, file.Name()), os.ModeDir)
    			//如果是目录,递归目录
    			return zipFolder(fileFolder, zw)
    		}
    		return zipFile(zipPath, zw)
    	})
    }
    
    // 解压缩函数
    func zipFile(sourceFile string, zw *zip.Writer) error {
    	sfile, err := os.Open(sourceFile)
    	if err != nil {
    		fmt.Println(err)
    		return err
    	}
    	defer sfile.Close()
    
    	info, err := sfile.Stat()
    	if err != nil {
    		fmt.Println(err)
    		return err
    	}
    	// 获取压缩头信息
    	header, err := zip.FileInfoHeader(info)
    	if err != nil {
    		fmt.Println(err)
    		return err
    	}
    	// 指定文件压缩方式 默认为 Store 方式 该方式不压缩文件 只是转换为zip保存
    	header.Method = zip.Deflate
    	header.Name = sourceFile
    	fw, err := zw.CreateHeader(header)
    	if err != nil {
    		fmt.Println(err)
    		return err
    	}
    	// 写入文件到压缩包中
    	_, err = io.Copy(fw, sfile)
    	if err != nil {
    		fmt.Println(err)
    		return err
    	}
    	return nil
    }
    
    //untarFile 解压
    func unZipFile(zipFile string, unzipPath string) error {
    	//打开要解包的文件,tarFile是要解包的 .tar 文件的路径
    	reader, err := zip.OpenReader(zipFile)
    	if err != nil {
    		fmt.Println(err)
    	}
    	//用 tr.Next() 来遍历包中的文件,然后将文件的数据保存到磁盘中
    	for _, file := range reader.File {
    		rc, err := file.Open()
    		//先创建目录
    		fileName := unzipPath + "/" + file.Name
    		dir := path.Dir(fileName)
    		_, err = os.Stat(dir)
    		//如果err 为空说明文件夹已经存在,就不用创建
    		if err != nil {
    			err = os.MkdirAll(dir, os.ModePerm)
    			if err != nil {
    				fmt.Println(err)
    				return err
    			}
    		}
    		//创建空文件,准备写入解压后的数据
    		fw, er := os.Create(fileName)
    		if er != nil {
    			fmt.Println(err)
    			return er
    		}
    		defer fw.Close()
    		// 写入解压后的数据
    		_, er = io.CopyN(fw, rc, int64(file.UncompressedSize64))
    		if er != nil {
    			return er
    		}
    	}
    	return nil
    }
    
    Songzhibin
  • 相关阅读:
    关于这个 blog
    P6499 [COCI2016-2017#2] Burza 题解
    CF1172F Nauuo and Bug 题解
    CF1479D Odd Mineral Resource 题解
    CF1442E Black, White and Grey Tree 题解
    CF1442D Sum 题解
    CF1025D Recovering BST 题解
    CF1056E Check Transcription 题解
    CF1025F Disjoint Triangles 题解
    红包算法的PHP实现
  • 原文地址:https://www.cnblogs.com/binHome/p/12573851.html
Copyright © 2020-2023  润新知