go语言的魔幻旅程25-archive包

送君千里,终须一别

go的基础类库方面的学习从本章节过后可能会告一个段落,后续的学习过程中如果发现还存在一些需要掌握的包可能会加以补充,相信经过前面一些包的讲解,go的重要的包应该基本上囊括了,根据本人的学习经验来讲,如果之前讲解的基本的语法和后续的基础包部分的内容都掌握的话,那么go的学习已经完成了第一个过程,go这门语言基本上可以说是入门了。剩下的内容我这里不可能全部讲解到,授人以鱼不如授人以渔,最后我还是想说:师父领进门修行在个人。

go语言的archive包

针对文件的操作过程中,打包和压缩是不可缺少的重要部分,下面这对这两个包的函数和方法展开讲解。

archive/tar

package main

/**********************************************************************/
/**************** golang中archive/tar包相关API讲解 ******************/
/********************************************************************/

/*
Constants
Variables
type Format
	func (f Format) String() string
type Header
	func FileInfoHeader(fi fs.FileInfo, link string) (*Header, error)
	func (h *Header) FileInfo() fs.FileInfo
type Reader
	func NewReader(r io.Reader) *Reader
	func (tr *Reader) Next() (*Header, error)
	func (tr *Reader) Read(b []byte) (int, error)
type Writer
	func NewWriter(w io.Writer) *Writer
	func (tw *Writer) Close() error
	func (tw *Writer) Flush() error
	func (tw *Writer) Write(b []byte) (int, error)
	func (tw *Writer) WriteHeader(hdr *Header) error
*/

func main() {

	/**
	*根据f的值,返回压缩的格式名称
	*func (f Format) String() string
	 */

	/*
		f := tar.FormatPAX
		s := f.String()
		fmt.Println(s)
	*/

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

	/*
		fileinfo , err := os.Stat("test.txt")
		if err != nil {
			fmt.Println(err)
		}

		h, err := tar.FileInfoHeader(fileinfo, "")
		h.Linkname = "haha"
		h.Gname = "test"
		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返回该Header对应的文件信息。(os.FileInfo类型)
	*func (h *Header) FileInfo() fs.FileInfo
	*/

	/*
	f, err := os.Open("sdk/test.tar")
	if err != nil {
		fmt.Println(err)
		return
	}

	defer f.Close()
	r := tar.NewReader(f)
	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())
	}
	*/


	/**
	*NewReader创建一个从r读取的Reader。
	*func NewReader(r io.Reader) *Reader
	*/

	/*
	s := strings.NewReader("hello")
	r := tar.NewReader(s)
	fmt.Println(r)
	*/

	/**
	*转入tar档案文件下一记录,它会返回下一记录的头域
	*func (tr *Reader) Next() (*Header, error)
	*/

	/*
	r := tar.NewReader(strings.NewReader("test.tar"))
	h, err := r.Next()
	fmt.Println(h, err)
	*/

	/**
	*转入tar档案文件下一记录,它会返回下一记录的头域
	*func (tr *Reader) Read(b []byte) (int, error)
	*/

	/*
	n, err := tar.NewReader(strings.NewReader("test.log")).Read(make([]byte, 0))
	fmt.Println(n, err)
	*/

	/**
	*NewWriter创建一个写入w的*Writer。
	*func NewWriter(w io.Writer) *Writer
	*/

	/*
	f, err := os.Create("sdk/demo.tar")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer f.Close()
	tw := tar.NewWriter(f)
	defer tw.Close()
	*/


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

	/*
		f, err := os.Create("sdk/demo.tar")
		if err != nil {
			fmt.Println(err)
			return
		}
		defer f.Close()
		tw := tar.NewWriter(f)
		defer tw.Close()
	*/


	/**
	*Flush结束当前文件的写入。
	*func (tw *Writer) Flush() error
	*/

	/*
	f, err := os.Create("sdk/demo.tar")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer f.Close()
	tw := tar.NewWriter(f)
	tw.Flush()
	defer tw.Close()
	*/

	/**
	*Write向tar档案文件的当前记录中写入数据。如果写入的数据总数超出上一次调用WriteHeader
	*的参数hdr.Size字节,返回ErrWriteTooLong错误。
	*func (tw *Writer) Write(b []byte) (int, error)
	*/

	/*
	buf := new(bytes.Buffer)
	tw := tar.NewWriter(buf)
	var files = []struct {
		Name, Body string
	}{
		{"readme.txt", "This archive contains some text files."},
		{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
		{"todo.txt", "Get animal handling license."},
	}
	for _, file := range files {
		hdr := &tar.Header{
			Name: file.Name,
			Mode: 0600,
			Size: int64(len(file.Body)),
		}
		if err := tw.WriteHeader(hdr); err != nil {
			log.Fatalln(err)
		}
		if _, err := tw.Write([]byte(file.Body)); err != nil {
			log.Fatalln(err)
		}
	}
	// 确保在Close时检查错误。
	if err := tw.Close(); err != nil {
		log.Fatalln(err)
	}

	// 打开tar档案以供阅读。
	r := bytes.NewReader(buf.Bytes())
	tr := tar.NewReader(r)

	// 迭代档案中的文件。
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			// tar归档结束
			break
		}
		if err != nil {
			log.Fatalln(err)
		}
		fmt.Printf("Contents of %s:\n", hdr.Name)
		if _, err := io.Copy(os.Stdout, tr); err != nil {
			log.Fatalln(err)
		}
		fmt.Println()
	}
	*/

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

	/*
	buf := new(bytes.Buffer)
	tw := tar.NewWriter(buf)
	var files = []struct {
		Name, Body string
	}{
		{"readme.txt", "This archive contains some text files."},
		{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
		{"todo.txt", "Get animal handling license."},
	}
	for _, file := range files {
		hdr := &tar.Header{
			Name: file.Name,
			Mode: 0600,
			Size: int64(len(file.Body)),
		}
		if err := tw.WriteHeader(hdr); err != nil {
			log.Fatalln(err)
		}
		if _, err := tw.Write([]byte(file.Body)); err != nil {
			log.Fatalln(err)
		}
	}
	if err := tw.Close(); err != nil {
		log.Fatalln(err)
	}
	r := bytes.NewReader(buf.Bytes())
	tr := tar.NewReader(r)
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			// tar归档结束
			break
		}
		if err != nil {
			log.Fatalln(err)
		}
		fmt.Printf("Contents of %s:\n", hdr.Name)
		if _, err := io.Copy(os.Stdout, tr); err != nil {
			log.Fatalln(err)
		}
		fmt.Println()
	}
	*/
}
复制代码

archive/zip

package main

/*********************************************************************/
/**************** golang中archive/zip包相关API讲解 *****************/
/********************************************************************/

/*
Constants
Variables
func RegisterCompressor(method uint16, comp Compressor)
func RegisterDecompressor(method uint16, dcomp Decompressor)
type Compressor
type Decompressor
type File
	func (f *File) DataOffset() (offset int64, err error)
	func (f *File) Open() (io.ReadCloser, error)
type FileHeader
	func FileInfoHeader(fi fs.FileInfo) (*FileHeader, error)
	func (h *FileHeader) FileInfo() fs.FileInfo
	func (h *FileHeader) ModTime() time.Time
	func (h *FileHeader) Mode() (mode fs.FileMode)
	func (h *FileHeader) SetModTime(t time.Time)
	func (h *FileHeader) SetMode(mode fs.FileMode)
type ReadCloser
	func OpenReader(name string) (*ReadCloser, error)
	func (rc *ReadCloser) Close() error
type Reader
	func NewReader(r io.ReaderAt, size int64) (*Reader, error)
	func (r *Reader) Open(name string) (fs.File, error)
	func (z *Reader) RegisterDecompressor(method uint16, dcomp Decompressor)
type Writer
	func NewWriter(w io.Writer) *Writer
	func (w *Writer) Close() error
	func (w *Writer) Create(name string) (io.Writer, error)
	func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error)
	func (w *Writer) Flush() error
	func (w *Writer) RegisterCompressor(method uint16, comp Compressor)
	func (w *Writer) SetComment(comment string) error
	func (w *Writer) SetOffset(n int64)
*/

func main() {

	/**
	*RegisterCompressor使用指定的方法ID注册一个Compressor类型函数。常用的方法Store和Deflate是内建的。
	*func RegisterCompressor(method uint16, comp Compressor)
	*/

	/*
	buf := new(bytes.Buffer)
	w := zip.NewWriter(buf)
	w.RegisterCompressor(zip.Deflate, func(out io.Writer) (io.WriteCloser, error) {
		return flate.NewWriter(out, flate.BestCompression)
	})
	*/

	/**
	*RegisterDecompressor使用指定的方法ID注册一个Decompressor类型函数
	*func RegisterDecompressor(method uint16, dcomp Decompressor)
	*/


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



	/**
	*Open方法返回一个io.ReadCloser接口,提供读取文件内容的方法。可以同时读取多个文件
	*func (f *File) Open() (io.ReadCloser, error)
	*/



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

	/*
	fileInfo, _ := os.Stat("sdk/test.txt")
	h, _ := zip.FileInfoHeader(fileInfo)
	fmt.Println(h.Name, h.Comment, h.CreatorVersion, h.Mode(), h.Modified, h.FileInfo().Name())
	*/


	/**
	*FileInfo返回一个根据h的信息生成的os.FileInfo。
	*func (h *FileHeader) FileInfo() fs.FileInfo
	*/

	/*
	fileInfo, _ := os.Stat("sdk/test.txt")
	h, _ := zip.FileInfoHeader(fileInfo)
	fmt.Println(h.Name, h.Comment, h.CreatorVersion, h.Mode(), h.Modified, h.FileInfo().Name())
	*/

	/**
	*返回最近一次修改的UTC时间。(精度2s)
	*func (h *FileHeader) ModTime() time.Time
	*/

	/*
	fileInfo, _ := os.Stat("sdk/test.txt")
	h, _ := zip.FileInfoHeader(fileInfo)
	fmt.Println(h.Name, h.Comment, h.CreatorVersion, h.Mode(), h.Modified, h.FileInfo().Name(), h.ModTime())
	*/

	/**
	*Mode返回h的权限和模式位。
	*func (h *FileHeader) Mode() (mode fs.FileMode)
	*/

	/*
	fileInfo, _ := os.Stat("sdk/test.txt")
	h, _ := zip.FileInfoHeader(fileInfo)
	fmt.Println(h.Name, h.Comment, h.CreatorVersion, h.Mode(), h.Modified, h.FileInfo().Name(), h.ModTime())
	*/

	/**
	*将ModifiedTime和ModifiedDate字段设置为给定的UTC时间。(精度2s)
	*func (h *FileHeader) SetModTime(t time.Time)
	*/

	/*
	fileInfo, _ := os.Stat("sdk/test.txt")
	h, _ := zip.FileInfoHeader(fileInfo)
	fmt.Println(h.Name, h.Comment, h.CreatorVersion, h.Mode(), h.Modified, h.FileInfo().Name(), h.ModTime())
	*/

	/**
	*SetMode修改h的权限和模式位。
	*func (h *FileHeader) SetMode(mode fs.FileMode)
	*/

	/*
	fileInfo, _ := os.Stat("sdk/test.txt")
	h, _ := zip.FileInfoHeader(fileInfo)
	fmt.Println(h.Name, h.Comment, h.CreatorVersion, h.Mode(), h.Modified, h.FileInfo().Name(), h.ModTime())
	*/


	/**
	*OpenReader会打开name指定的zip文件并返回一个*ReadCloser。
	*func OpenReader(name string) (*ReadCloser, error)
	*/

	/*
	const  FILE = "sdk/test.zip"
	const DIR = "sdk/tmp/"
	rd, _ := zip.OpenReader(FILE)
	defer rd.Close()

	for _, file := range rd.File {
		rc, _ := file.Open()
		f, _ := os.Create(DIR+file.Name)
		n, _ := io.Copy(f, rc)
		fmt.Println(n)
	}
	*/

	/**
	*Close关闭zip文件,使它不能用于I/O。
	*func (rc *ReadCloser) Close() error
	*/

	/*
	const  FILE = "sdk/test.zip"
	const DIR = "sdk/tmp/"
	rd, _ := zip.OpenReader(FILE)
	defer rd.Close()
	*/

	/**
	*NewReader返回一个从r读取数据的*Reader,r被假设其大小为size字节
	*func NewReader(r io.ReaderAt, size int64) (*Reader, error)
	*/

	/*
	buf := &bytes.Buffer{}
	b := bytes.NewReader(buf.Bytes())
	r, err := zip.NewReader(b, int64(b.Len()))
	fmt.Println(r, err)
	*/

	/**
	*Open使用fs.FS.Open的语义在ZIP存档中打开命名文件:路径始终以斜杠分隔,没有前导/或../元素。
	*func (r *Reader) Open(name string) (fs.File, error)
	*/

	/**
	*RegisterDecompressor为特定的方法ID注册或覆盖自定义解压缩器。如果找不到给定方法的解压缩器,
	*则Reader将默认在包级别查找该解压缩器。
	*func (z *Reader) RegisterDecompressor(method uint16, dcomp Decompressor)
	*/

	/**
	*NewWriter创建并返回一个将zip文件写入w的*Writer。
	*func NewWriter(w io.Writer) *Writer
	*/


	/*
	buf := new(bytes.Buffer)
	w := zip.NewWriter(buf)
	var files = []struct {
		Name, Body string
	}{
		{"readme.txt", "This archive contains some text files."},
		{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
		{"todo.txt", "Get animal handling licence.\nWrite more examples."},
	}
	for _, file := range files {
		f, err := w.Create(file.Name)
		if err != nil {
			log.Fatal(err)
		}
		_, err = f.Write([]byte(file.Body))
		if err != nil {
			log.Fatal(err)
		}
	}
	err := w.Close()
	if err != nil {
		log.Fatal(err)
	}
	*/


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

	/*
		buf := new(bytes.Buffer)
		w := zip.NewWriter(buf)
		var files = []struct {
			Name, Body string
		}{
			{"readme.txt", "This archive contains some text files."},
			{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
			{"todo.txt", "Get animal handling licence.\nWrite more examples."},
		}
		for _, file := range files {
			f, err := w.Create(file.Name)
			if err != nil {
				log.Fatal(err)
			}
			_, err = f.Write([]byte(file.Body))
			if err != nil {
				log.Fatal(err)
			}
		}
		err := w.Close()
		if err != nil {
			log.Fatal(err)
		}
	*/


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

	/*
		buf := new(bytes.Buffer)
		w := zip.NewWriter(buf)
		var files = []struct {
			Name, Body string
		}{
			{"readme.txt", "This archive contains some text files."},
			{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
			{"todo.txt", "Get animal handling licence.\nWrite more examples."},
		}
		for _, file := range files {
			f, err := w.Create(file.Name)
			if err != nil {
				log.Fatal(err)
			}
			_, err = f.Write([]byte(file.Body))
			if err != nil {
				log.Fatal(err)
			}
		}
		err := w.Close()
		if err != nil {
			log.Fatal(err)
		}
	*/


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


	/**
	*刷新将所有缓冲的数据刷新到基础写入器。通常不需要调用Flush。调用Close就足够了。
	*func (w *Writer) Flush() error
	 */

	/**
	*RegisterCompressor注册或覆盖用于特定方法ID的自定义压缩器。如果找不到用于给定方法的压缩器,
	*Writer将默认在包级别查找该压缩器。
	*func (w *Writer) RegisterCompressor(method uint16, comp Compressor)
	*/

	/*
	buf := new(bytes.Buffer)
	w := zip.NewWriter(buf)
	w.RegisterCompressor(zip.Deflate, func(out io.Writer) (io.WriteCloser, error) {
		return flate.NewWriter(out, flate.BestCompression)
	})
	*/

	/**
	*SetComment设置中央目录末尾的注释字段。它只能在关闭之前调用。
	*func (w *Writer) SetComment(comment string) error
	*/


	/**
	*SetOffset设置基础编写器中zip数据开头的偏移量。将zip数据附加到现有文件(例如二进制可执行文件时,
	*应使用该文件。在写入任何数据之前必须先调用它。。
	*func (w *Writer) SetOffset(n int64)
	*/
}

复制代码

小结

关于文件的打包和压缩相关的应用场景还是非常多的,但是核心的思想都是围绕着文件流来展开相关的操作,希望这个部分的内容也拿下来。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享