zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    PDE_DATA 定义
    每天写日记争创青年艺术家 2014-5-14
    [Servlet3.0新功能]注释替代配置文件
    Flex4+Spring3+Hibernate3+BlazeDS整合笔记
    Flex博客
    hibernate缓存机制详细分析
    计算机的艺术-算法
    算法/数据结构/数学
    线性表 及Java实现 顺序表、链表、栈、队列
    java 图的邻接矩阵
  • 原文地址:https://www.cnblogs.com/binHome/p/12573851.html
Copyright © 2011-2022 走看看