当前位置:首页 > 文章列表 > Golang > Go教程 > Go archive/tar 怎样读取 tar 目录项的类型标志

Go archive/tar 怎样读取 tar 目录项的类型标志

来源:17golang原创 2026-10-18 06:36:04 0浏览 收藏

Go 读取 tar 成员类型时,先调用 tar.Reader.Next() 取得 Header,再比较 hdr.Typeflag 与 tar.TypeDir、tar.TypeReg 等常量。如果这里只想判断“是不是目录”,可以使用 hdr.FileInfo().IsDir();需要区分普通文件、链接或其他类型时,直接 switch Typeflag 更合适。

这里的“目录项”指 tar 归档中的成员,不是本机目录扫描返回的 os.DirEntry。本文只生成归档清单,不解包、不创建目录,也不根据链接目标继续读取磁盘。

官方文档:https://pkg.go.dev/archive/tar

做归档清单时,先明确要区分几种成员

仅统计目录数量,比较 TypeDir 就够了;需要把归档内容交给后续业务,最好保留细分类别。普通文件、硬链接和符号链接都可能“不是目录”,但三者的数据和目标语义并不相同。把所有非目录项都当成普通文件,会在链接或特殊成员上做出错误选择。

// hdr必须来自一次成功的Next调用,不能忽略其错误。
if hdr.Typeflag == tar.TypeDir {
    // 此处只处理归档内的目录成员,不触碰磁盘。
    fmt.Printf("目录:%q\n", hdr.Name)
}

上面是需放进读取循环的片段,不是独立程序。TypeDir 的值是字符 '5',不是整数 5;应使用具名常量避免混淆。Typeflag 也不是 Mode 权限位,不要用 0755 这样的权限数字判断成员类型。

Header字段与目录普通文件和链接类别的静态对应关系
图1:tar Header 类型结构说明图。Typeflag 表示类别,Name 和 Linkname 提供不同元数据,不是解包执行流程。

Typeflag、IsDir 与名称后缀怎样选择

方式适合的任务不足
switch hdr.Typeflag区分目录、普通文件、硬链接、符号链接及其他成员需要保留未知类型分支
hdr.FileInfo().IsDir()只需要目录布尔值的通用文件信息接口false不能说明一定是普通文件
检查 Name 是否以 / 结尾观察命名约定或研究旧格式不是完整的tar类型判断方案

建议把 Typeflag 作为 tar 语义分类入口,FileInfo 作为需要 fs.FileInfo 时的适配。FileInfo 来源仍是 Header,不会去本地文件系统判断路径是否存在,也不会跟随归档里的符号链接检查目标是不是目录。

名称末尾的斜杠与目录有关联,但不要据此覆盖读取器给出的类别。即使某个生产工具始终在目录名后加斜杠,这也是该工具的输出习惯,不是你可以忽略 Typeflag 的理由。

一段只读清单程序,未知标志也不丢失

下面完整程序从标准输入读取未压缩 tar 流,逐项输出名称、类型、原始返回标志、Size 和 Linkname。代码未实际运行,展示的是接口使用方法,不含运行日志。

package main

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

// entryKind 保留不同成员类型,不把非目录统称为普通文件。
func entryKind(flag byte) string {
    switch flag {
    case tar.TypeDir:
        return "目录"
    case tar.TypeReg, tar.TypeRegA:
        // TypeRegA是旧式值,Reader通常已将它规范化。
        return "普通文件"
    case tar.TypeLink:
        return "硬链接"
    case tar.TypeSymlink:
        return "符号链接"
    case tar.TypeChar:
        return "字符设备"
    case tar.TypeBlock:
        return "块设备"
    case tar.TypeFifo:
        return "FIFO"
    default:
        return "其他类型"
    }
}

// listEntries 只读取元数据,不创建文件,不跟随链接。
func listEntries(r io.Reader, w io.Writer) error {
    tr := tar.NewReader(r)
    for {
        hdr, err := tr.Next()
        if err == io.EOF {
            return nil // 这是归档结束,不是单个成员内容结束。
        }
        if err != nil {
            return fmt.Errorf("读取tar成员: %w", err)
        }
        // %q转义名称中的换行等字符;十六进制标志便于保留未知类型。
        if _, err := fmt.Fprintf(w, "%q 类型=%s 标志=0x%02x 大小=%d 链接=%q\n",
            hdr.Name, entryKind(hdr.Typeflag), hdr.Typeflag, hdr.Size, hdr.Linkname); err != nil {
            return fmt.Errorf("输出清单: %w", err)
        }
        // 不读取正文;下一次Next会丢弃当前成员未读的数据。
    }
}

func main() {
    // 标准输入、输出由调用方管理;本程序不关闭它们。
    if err := listEntries(os.Stdin, os.Stdout); err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}

读者可将完整程序保存为 main.go,并自行准备可信的 sample.tar。下面命令只用于读取,不会提取成员:

# 将未压缩tar送入清单程序,不会写出归档成员。
go run main.go 

输出中的 0x35 对应字符 '5',0x30 对应字符 '0'。将标志打印成十六进制,比打印不可见的零字节更容易观察。名称和链接使用 %q,避免其中的换行或控制字符直接破坏清单展示。

Next 返回 io.EOF 表示归档已结束;其他错误直接返回,不能用 continue 掩盖。当前程序对包括 ErrInsecurePath 在内的非 EOF 错误采用停止策略,不使用带错误返回的 Header。输出端错误也会向上传递。

Reader Next与Header元数据和错误输出的静态关系
图2:只读清单接口结构说明图。Reader 提供成员 Header,清单读取 Typeflag;EOF 和读取错误分别处理,不是运行截图。

读取器返回的标志,不一定等于磁盘上的原始字节

旧格式的 TypeRegA 是零字节,当前文档已将该常量标为弃用,编写新 Header 应使用 TypeReg。Go 的读取器实现会处理这种旧式标志:名称以 / 结尾时改为 TypeDir,否则改为 TypeReg。因此,正常经过 Reader.Next 后,通常不需要依靠 TypeRegA 分支猜目录。

清单程序仍显式兼容 TypeRegA,是为了让 entryKind 对单独构造的 Header 值也有可读解释;它不意味着 Next 一定会原样暴露旧字节。如果任务是取证式逐字节查看归档头,本例这种逻辑清单接口并不适合。

PAX 扩展记录、GNU 长名称记录等也会由读取器处理,不能假定每次 Next 都对应一个完全未经解释的原始头块。这里不扩展实现二进制解析器,只依据 Next 提供的 Header 解释成员。

读取器实现:https://go.dev/src/archive/tar/reader.go

链接不是目标内容,目录也不是空普通文件

tar.TypeLink 表示硬链接,tar.TypeSymlink 表示符号链接,链接目标保存在 Linkname。目标字符串不是本程序应该打开的磁盘路径;只做清单时,保留它即可。只看 Size 是否为零无法区分目录、空普通文件与链接。

对于 TypeDir、TypeLink、TypeSymlink 等头信息类型,Reader.Read 不会因此提供目标文件内容。清单程序无需把正文读到内存;Next 会自动丢弃前一成员尚未读取的数据。但底层流仍可能发生读取与跳过,不能将“没复制正文”理解成零I/O,也不能据此宣称极大归档处理没有资源代价。

未知标志使用“其他类型”并保留标志值。这个输出策略只适合观察;如果未来增加解包功能,应明确允许哪些类别,不能把 default 自动变成普通文件写入。Typeflag 分类本身也不解决路径约束、链接处理和大小上限问题。

用几种小成员复现分类,再决定接口

下列是供读者自行构造样本时核对的预期,不是已执行测试报告:

输入成员语义清单应关注的值不能据此推断
显式TypeDir目录Typeflag为TypeDir磁盘上已创建目录
零长度TypeReg文件普通文件,Size为0Size为0就是目录
TypeSymlink成员符号链接,保留Linkname链接目标存在或可访问
TypeLink成员硬链接,保留Linkname目标内容可以直接从该成员读取
损坏归档或输出端失败返回错误并停止已成功完整列出全包

为什么 IsDir 为 false 仍不能直接读成文件?

因为非目录包含链接、设备及其他类型。需要普通文件时应明确判断 TypeReg;对稀疏文件等扩展类别是否支持,应另外定义业务策略。

为什么循环里没有 io.Copy?

任务只是读取元数据,Next 会负责跨过剩余正文。需要消费成员内容时才在成功取得 Header 后读取当前 Reader,并处理该成员读取错误。

tar.gz 可以直接传给这个程序吗?

不可以,当前输入约定是未压缩 tar。压缩容器需要先由相应解压读取层提供 tar 字节流,本例不把压缩格式识别与成员分类混在一起。

最终选择可以很简短:只问“是不是目录”用 IsDir 或 TypeDir;需要完整 tar 类别用 Typeflag;名称后缀只作为观察信息。让分类、内容读取和落盘操作分别承担自己的职责,清单逻辑就不会被解包副作用拖复杂。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go embed 怎样处理嵌入文件不存在的错误Go embed 怎样处理嵌入文件不存在的错误
上一篇
Go embed 怎样处理嵌入文件不存在的错误
Go archive/tar Header.AccessTime 怎样保留文件访问时间
下一篇
Go archive/tar Header.AccessTime 怎样保留文件访问时间
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    513次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    572次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    598次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    550次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    368次使用