zoukankan      html  css  js  c++  java
  • Go标准库之tar

    tar包实现了tar格式压缩文件的存取。本包目标是覆盖大多数tar的变种,包括GNU和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'    // 稀疏文件
    )
    
    // Struct
        // Header
        // Header代表 tar 档案文件里的单个头。Header类型的某些字段可能未使用。表示tar存档中的单个头。
    type Header struct {
    	Typeflag   byte //记录头的类型
    	Name       string // 记录头域的文件名
    	Linkname   string // 链接的目标名
    	Size       int64  // 字节数(长度)
    	Mode       int64     // 权限和模式位
    	Uid        int       // 所有者的用户ID
    	Gid        int       // 所有者的组ID
    	ModTime    time.Time // 修改时间
    	Uname      string    // 所有者的用户名
    	Gname      string    // 所有者的组名
    	AccessTime time.Time // 访问时间
    	ChangeTime time.Time // 状态改变时间
    	Devmajor   int64     // 字符设备或块设备的major number
    	Devminor   int64     // 字符设备或块设备的minor number
    	Xattrs     map[string]string
    	PAXRecords map[string]string
    	Format     Format    //格式指定tar头的格式。这是由读者设置的。如果在调用writer.writeHeader时未指定格式,然后使用第一种格式(按照USTAR、PAX、GNU的顺序)能够对此头进行编码(Format)。
    }
            // Function:
                func (h *Header) FileInfo() os.FileInfo 
                // FileInfo返回该 Header 对应的文件信息。( os.FileInfo 类型)
    
        // Reader
        // Reader提供了对一个 tar 档案文件的顺序读取。一个 tar 档案文件包含一系列文件。 Next 方法返回档案中的下一个文件(包括第一个),返回值可以被视为 io.Reader 来获取文件的数据。
    type Reader struct {
    	r    io.Reader
    	pad  int64      // 当前文件项后的填充量(忽略)
    	curr fileReader // 当前文件项的读取器
    	blk  block      // 用作临时本地存储的缓冲区
    	err  error
    }
            // Function
                func (tr *Reader) Next() (*Header, error)
                // 转入 tar 档案文件下一记录,它会返回下一记录的头域。
                func (tr *Reader) Read(b []byte) (n int, err error)
                // 从档案文件的当前记录读取数据,到达记录末端时返回(0,EOF),直到调用 Next 方法转入下一记录。
    
    
         // Writer
         // Writer类型提供了POSIX.1格式的 tar 档案文件的顺序写入。一个 tar 档案文件包含一系列文件。调用 WriteHeader 来写入一个新的文件,然后调用 Write 写入文件的数据,该记录写入的数据不能超过hdr.Size字节。
    type Writer struct {
    	w    io.Writer
    	pad  int64      //当前文件项后要写入的填充量
    	curr fileWriter // 当前文件的写入器
    	hdr  Header     // 对突变安全的标题的浅拷贝
    	blk  block      // 用作临时本地存储的缓冲区
    	err  error
    }
            // Function
                func (tw *Writer) Close() error
                // Close关闭 tar 档案文件,会将缓冲中未写入下层的 io.Writer 接口的数据刷新到下层。
                func (tw *Writer) Flush() error
                // Flush结束当前文件的写入。(可选的)
                func (tw *Writer) Write(b []byte) (n int, err error)
                // Write向 tar 档案文件的当前记录中写入数据。如果写入的数据总数超出上一次调用 WriteHeader 的参数hdr.Size字节,返回ErrWriteTooLong错误。
                func (tw *Writer) WriteHeader(hdr *Header) error
                // WriteHeader写入hdr并准备接受文件内容。如果不是第一次调用本方法,会调用 Flush 。在 Close 之后调用本方法会返回ErrWriteAfterClose。
    
    
    // Function
        func FileInfoHeader(fi os.FileInfo, link string) (*Header, error)
        // FileInfoHeader返回一个根据fi填写了部分字段的Header。如果fi描述一个符号链接,FileInfoHeader函数将link参数作为链接目标。如果fi描述一个目录,会在名字后面添加斜杠。因为 os.FileInfo 接口的Name方法只返回它描述的文件的无路径名,有可能需要将返回值的Name字段修改为文件的完整路径名。
    
        func NewReader(r io.Reader) *Reader
        // NewReader创建一个从r读取的Reader。
    
        func NewWriter(w io.Writer) *Writer
        // NewWriter创建一个写入w的*Writer。
    

    Demo

    // Header信息读取
    func headerDemo() {
    	fileName := "./tarFile.tar"
    	sfileInfo, err := os.Stat(fileName)
    	if err != nil {
    		fmt.Println("get file status Err,", err)
    		return
    	}
    	header, err := tar.FileInfoHeader(sfileInfo, "")
    	if err != nil {
    		fmt.Println("get Header Info Err,", err)
    		return
    	}
    	fmt.Println(header.Name)
    	fmt.Println(header.Mode)
    	fmt.Println(header.Uid)
    	fmt.Println(header.Gid)
    	fmt.Println(header.Size)
    	fmt.Println(header.ModTime)
    	fmt.Println(header.Typeflag)
    	fmt.Println(header.Linkname)
    	fmt.Println(header.Uname)
    	fmt.Println(header.Gname)
    	fmt.Println(header.Devmajor)
    	fmt.Println(header.Devminor)
    	fmt.Println(header.AccessTime)
    	fmt.Println(header.ChangeTime)
    	fmt.Println(header.Xattrs)
    }
    
    
    // 打包函数例子
    
    func tarDemo() {
    	filetarget := "./tarFile.tar"
    	filesource := "./filedata"
    	tarfile, err := os.Create(filetarget)
    	if err != nil {
    		// if file is exist then delete file
    		if err == os.ErrExist {
    			if err := os.Remove(filetarget); err != nil {
    				fmt.Println(err)
    			}
    		} else {
    			fmt.Println(err)
    		}
    	}
    	defer tarfile.Close()
    	tarwriter := tar.NewWriter(tarfile)
    	sfileInfo, err := os.Stat(filesource)
    	if err != nil {
    		fmt.Println(err)
    	}
    	if !sfileInfo.IsDir() {
    		tarFile(filesource, sfileInfo, tarwriter)
    	} else {
    		tarFolder(filesource, tarwriter)
    	}
    }
    
    
    // tar 单个文件
    //压缩单个文件
    func tarFile(filesource string, sfileInfo os.FileInfo, tarwriter *tar.Writer) error {
    	sfile, err := os.Open(filesource)
    	if err != nil {
    		fmt.Println(err)
    		return err
    	}
    	defer sfile.Close()
    	header, err := tar.FileInfoHeader(sfileInfo, "")
    	if err != nil {
    		fmt.Println(err)
    		return err
    	}
    	header.Name = filesource
    	err = tarwriter.WriteHeader(header)
    	if err != nil {
    		fmt.Println(err)
    		return err
    	}
    	if _, err = io.Copy(tarwriter, sfile); err != nil {
    		fmt.Println(err)
    		return err
    	}
    	return nil
    }
    
    // tar 一个目录
    //压缩文件夹
    func tarFolder(directory string, tarwriter *tar.Writer) error {
    	return filepath.Walk(directory, func(targetpath string, file os.FileInfo, err error) error {
    		//read the file failure
    		if file == nil {
    			return err
    		}
    		if file.IsDir() {
    			if directory == targetpath {
    				return nil
    			}
    			header, err := tar.FileInfoHeader(file, "")
    			if err != nil {
    				return err
    			}
    			header.Name = filepath.Join(directory, strings.TrimPrefix(targetpath, directory))
    			if err = tarwriter.WriteHeader(header); err != nil {
    				return err
    			}
    			os.Mkdir(strings.TrimPrefix(directory, file.Name()), os.ModeDir)
    			//如果压缩的目录里面还有目录,则递归压缩
    			return tarFolder(targetpath, tarwriter)
    		}
    		return tarFile(targetpath, file, tarwriter)
    	})
    }
    
    解压
    
    func untarFile(tarFile string, untarPath string) error {
    	//打开要解包的文件,tarFile是要解包的 .tar 文件的路径
    	fr, er := os.Open(tarFile)
    	if er != nil {
    		return er
    	}
    	defer fr.Close()
    	// 创建 tar.Reader,准备执行解包操作
    	tr := tar.NewReader(fr)
    	//用 tr.Next() 来遍历包中的文件,然后将文件的数据保存到磁盘中
    	for hdr, er := tr.Next(); er != io.EOF; hdr, er = tr.Next() {
    		if er != nil {
    			return er
    		}
    		//先创建目录
    		fileName := untarPath + "/" + hdr.Name
    		dir := path.Dir(fileName)
    		_, err := os.Stat(dir)
    		//如果err 为空说明文件夹已经存在,就不用创建
    		if err != nil {
    			err = os.MkdirAll(dir, os.ModePerm)
    			if err != nil {
    				fmt.Print(err)
    				return err
    			}
    		}
    		//获取文件信息
    		fi := hdr.FileInfo()
    		//创建空文件,准备写入解压后的数据
    		fw, er := os.Create(fileName)
    		if er != nil {
    			return er
    		}
    		defer fw.Close()
    		// 写入解压后的数据
    		_, er = io.Copy(fw, tr)
    		if er != nil {
    			return er
    		}
    		// 设置文件权限
    		os.Chmod(fileName, fi.Mode().Perm())
    	}
    	return nil
    }
    
    
    Songzhibin
  • 相关阅读:
    hdu 1312 ( Red and Black )
    hdu 1429 ( 胜利大逃亡(续) )
    zjut 小X的苹果
    hdu 1253 ( 胜利大逃亡 )
    许多事
    1198 ( Farm Irrigation )
    hdu 1241 Oil Deposits
    hdu 1242 ( Rescue )
    hdu 1240 ( Asteroids! )
    zoj2966 build the electric system
  • 原文地址:https://www.cnblogs.com/binHome/p/12573737.html
Copyright © 2011-2022 走看看