golang中archive/tar包详解

简介: golang、archive/tar

go语言官方标准库提供tar库,以方便对tar的操作

一、了解tar
什么是tar?
tar是一种打包格式,但不对文件进行压缩,所以打包后的文档一般远远大于zip和tar.gz,因为不需要压缩的原因,所以打包的速度是非常快的,打包时CPU占用率也很低。

tar的目的是什么?
方便文件的管理(帮助理解:就是你存在很多文件的时候,但是你很多要很长时间不去接触的话,你想要变得更加简洁,可以进行tar操作,就可以变得更简洁,比如就像生活中,有很多小箱子分散在不同的房间里,可以将小箱子叠起来放在一个房间里,tar可以类似这样)
下面一张图可以帮助很好的理解
image.png
(说明:图片来自维基百科,链接https://zh.wikipedia.org/wiki/Tar)

二、tar的操作
打包、解包

三、go如何对tar文件操作
打包操作:
1、生成打包后的目标文件
2、获取要打包的文件集
3、往目标文件写入文件

接着给出一个代码案例:

package main

import (
    "log"
    "os"
    "archive/tar"
    "io"
)

func main() {
    dst := "D:\\go_code\\video_server\\src\\a.tar"
    if err := Tar([]string{"D:\\go_code\\video_server\\src\\main.go", "D:\\go_code\\video_server\\src\\t.go"}, dst);err != nil {
        log.Fatal(err)
    }
}

func Tar(src []string, dst string) error {
    // 创建tar文件
    fw, err := os.Create(dst)
    if err != nil {
        return err
    }
    defer fw.Close()

    // 通过fw创建一个tar.Writer
    tw := tar.NewWriter(fw)
    // 如果关闭失败会造成tar包不完整
    defer func() {
        if err := tw.Close();err != nil {
            log.Println(err)
        }
    }()

    for _, fileName := range src {
        fi, err := os.Stat(fileName)
        if err != nil {
            log.Println(err)
            continue
        }
        hdr, err := tar.FileInfoHeader(fi, "")
        // 将tar的文件信息hdr写入到tw
        err = tw.WriteHeader(hdr)
        if err != nil {
            return err
        }

        // 将文件数据写入
        fs, err := os.Open(fileName)
        if err != nil {
            return err
        }
        if _, err = io.Copy(tw, fs);err != nil {
            return err
        }
        fs.Close()
    }
    return nil
}

解包操作:
1、打开tar文件
2、遍历tar中文件信息
3、创建文件,写入,保存,关闭文件

接着给出一个代码案例:

package main

import (
    "os"
    "log"
    "archive/tar"
    "io"
)

func main() {
    srcFile := "a.tar"
    // 打开 tar 包
    fr, err := os.Open(srcFile)
    if err != nil {
        log.Fatal(err)
    }
    defer fr.Close()

    tr := tar.NewReader(fr)
    for hdr, err := tr.Next();err != io.EOF;hdr, err = tr.Next() {
        if err != nil {
            log.Println(err)
            continue
        }
        // 读取文件信息
        fi := hdr.FileInfo()

        // 创建一个空文件,用来写入解包后的数据
        fw, err := os.Create(fi.Name())
        if err != nil {
            log.Println(err)
            continue
        }

        if _, err := io.Copy(fw, tr);err != nil {
            log.Println(err)
        }
        os.Chmod(fi.Name(), fi.Mode().Perm())
        fw.Close()
    }
}

四、tar包深入学习(作为一名计算机专业人士,至少要知道原理和实现的,接着我们来分析下原理和实现)
打包和解包的原理和实现
1、打包实现原理
先创建一个文件x.tar,然后向x.tar写入tar头部信息。打开要被tar的文件,向x.tar写入头部信息,然后向x.tar写入文件信息。重复第二步直到所有文件都被写入到x.tar中,关闭x.tar,整个过程就这样完成了

2、解包实现原理
先打开tar文件,然后从这个tar头部中循环读取存储在这个归档文件内的文件头信息,从这个文件头里读取文件名,以这个文件名创建文件,然后向这个文件里写入数据

3、go标准库解包实现代码详解

打包:
// 接下来对底层实现进行分析
tr := tar.NewReader(fr)
hdr, err := tar.FileInfoHeader(fi, "")
// 将tar的文件信息hdr写入到tw
err = tw.WriteHeader(hdr)

解包:
    fr, err := os.Open(srcFile)
    tr := tar.NewReader(fr)
    hdr, err := tr.Next()
    fi := hdr.FileInfo()
    fw, err := os.Create(fi.Name())
    io.Copy(fw, tr)
    os.Chmod(fi.Name(), fi.Mode().Perm())
// 看一遍代码可能不能深入理解,只有自己是实现一遍才能深入理解
// go 标准库封装windows、linux、FreeBSD、mac四类操作系统底层细节操作,因为不同的系统对文件存储方式不同,所以定义了下面这些常量
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'    // 稀疏文件
)
// 有四个变量,分别是写内容太多,头部信息太长,关闭错误,以及无效tar头部信息
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")
)

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     // 字符设备或块设备的major number
    Devminor   int64     // 字符设备或块设备的minor number
    AccessTime time.Time // 访问时间
    ChangeTime time.Time // 状态改变时间
    Xattrs     map[string]string
}

五、相关参考链接
Golang 学习笔记(四)- archive/tar 实现打包压缩及解压:
1)https://golangcaff.com/articles/151/golang-learning-notes-four-archivetar-package-compression-and-decompression
2)https://broqiang.com/posts/45

如果此文对你有稍许的帮助,谢谢点赞和关注,对go语言精通之路有兴趣的可以加我qq:761774955,相互交流学习

目录
相关文章
|
7月前
|
监控 网络协议 Go
Golang抓包:实现网络数据包捕获与分析
Golang抓包:实现网络数据包捕获与分析
|
8月前
|
负载均衡 中间件 Go
Golang 微服务工具包 Go kit
Golang 微服务工具包 Go kit
54 0
|
8天前
|
移动开发 Go
golang bufio包怎么用?
`bufio` 是 Go 语言中用于提高 I/O 性能的包,它通过使用缓冲区减少对低效磁盘 I/O 操作的调用。简而言之,`bufio` 提供带缓冲的读写功能,减少读取或写入文件时的系统调用次数,从而提升程序性能。
|
1月前
|
XML JSON Go
Golang深入浅出之-XML处理在Go语言中的实现:encoding/xml包
【4月更文挑战第26天】Go语言的`encoding/xml`库提供XML处理,包括序列化和反序列化。本文讨论了XML处理的基础,如`xml.Marshal`和`xml.Unmarshal`函数,以及常见问题和易错点,如标签命名、结构体嵌套、omitempty标签和命名空间。建议遵循标签命名规则,正确处理嵌套和属性,谨慎使用omitempty,以及理解并有效利用命名空间。文中还给出了基础示例和处理XML属性的代码示例,帮助读者掌握XML处理技巧。
36 1
Golang深入浅出之-XML处理在Go语言中的实现:encoding/xml包
|
1月前
|
监控 Go 开发者
Golang深入浅出之-Goroutine泄漏检测与避免:pprof与debug包
【5月更文挑战第2天】本文介绍了Go语言并发编程中可能遇到的Goroutine泄漏问题,以及如何使用`pprof`和`debug`包来检测和防止这种泄漏。常见的问题包括忘记关闭channel和无限制创建goroutine。检测方法包括启动pprof服务器以监控Goroutine数量,使用`debug.Stack()`检查堆栈,以及确保每个Goroutine有明确的结束条件。通过这些手段,开发者可以有效管理Goroutine,维持程序性能。
74 7
|
1月前
|
Java Go
Golang深入浅出之-Goroutine泄漏检测与避免:pprof与debug包
【5月更文挑战第1天】本文介绍了Go语言中goroutine泄漏的问题及其影响,列举了忘记关闭通道、无限循环和依赖外部条件等常见泄漏原因。通过引入`net/http/pprof`和`runtime/debug`包,可以检测和避免goroutine泄漏。使用pprof的HTTP服务器查看goroutine堆栈,利用`debug`包的`SetGCPercent`和`FreeOSMemory`函数管理内存。实践中,应使用`sync.WaitGroup`、避免无限循环和及时关闭通道来防止泄漏。理解这些工具和策略对维护Go程序的稳定性至关重要。
46 4
|
1月前
|
安全 测试技术 Go
Golang深入浅出之-Go语言单元测试与基准测试:testing包详解
【4月更文挑战第27天】Go语言的`testing`包是单元测试和基准测试的核心,简化了测试流程并鼓励编写高质量测试代码。本文介绍了测试文件命名规范、常用断言方法,以及如何进行基准测试。同时,讨论了测试中常见的问题,如状态干扰、并发同步、依赖外部服务和测试覆盖率低,并提出了相应的避免策略,包括使用`t.Cleanup`、`t.Parallel()`、模拟对象和检查覆盖率。良好的测试实践能提升代码质量和项目稳定性。
28 1
|
1月前
|
Go API 开发者
Golang深入浅出之-文件与目录操作:os与path/filepath包
【4月更文挑战第26天】Go语言标准库`os`和`path/filepath`提供文件读写、目录操作等功能。本文涵盖`os.Open`, `os.Create`, `os.Mkdir`, `filepath.Join`等API的使用,强调了文件关闭、路径处理、并发写入和权限问题的处理,并给出实战代码示例,帮助开发者高效、安全地操作文件与目录。注意使用`defer`关闭文件,`filepath`处理路径分隔符,以及通过同步机制解决并发写入冲突。
40 2
|
1月前
|
安全 Unix Go
Golang深入浅出之-Go语言中的时间与日期处理:time包详解
【4月更文挑战第26天】Go语言的`time`包提供处理日期和时间的功能,包括`time.Time`类型、时间戳、格式化与解析。本文讨论了核心概念、常见问题(如时区处理、格式字符串混淆、超时控制和并发安全)及解决方法。推荐使用`time.LoadLocation`管理时区,熟悉时间格式规则,用`context`精确控制超时,并注意并发安全。文中通过代码示例展示了如何获取格式化时间、计算时间差以及创建定时任务。学习和应用这些知识可提高程序的健壮性和准确性。
46 2
|
1月前
|
JSON 编解码 Go
Golang深入浅出之-HTTP客户端编程:使用net/http包发起请求
【4月更文挑战第25天】Go语言`net/http`包提供HTTP客户端和服务器功能,简化高性能网络应用开发。本文探讨如何发起HTTP请求,常见问题及解决策略。示例展示GET和POST请求的实现。注意响应体关闭、错误处理、内容类型设置、超时管理和并发控制。最佳实践包括重用`http.Client`,使用`context.Context`,处理JSON以及记录错误日志。通过实践这些技巧,提升HTTP编程技能。
32 1