Go archive/tar 怎样写入目录和文件模式
Go archive/tar 写目录时,明确设置 Typeflag: tar.TypeDir、目录条目名和零大小;写普通文件时用 tar.TypeReg,把八进制权限写入 Header.Mode,并让 Size 等于内容的字节数。目录类型与权限由不同字段表达,不能把整个 Go 文件模式强转后直接塞入 Mode。
官方文档:https://pkg.go.dev/archive/tar
遇到空目录丢失或脚本没有执行位,先看头部字段
部署包展开后少了 cache 空目录,先确认归档里有没有独立目录条目。只写子文件路径可以表达层级,却无法代表没有文件的目录。脚本无法执行则要区分归档记录的模式和解包后的实际权限,避免直接把全部文件改成 0777。
本文用一个小型交付包串起判断、处理与失败回退。代码为原创示例,尚未执行;图片是静态说明图,不代表运行结果。
| 条目 | 类型 | Mode | Size |
|---|---|---|---|
| bundle/ | TypeDir | 0755 | 0 |
| bundle/cache/ | TypeDir | 0750 | 0 |
| bundle/settings.txt | TypeReg | 0640 | 正文的字节数 |
| bundle/start.sh | TypeReg | 0750 | 脚本的字节数 |
快速判断:类型、权限和大小分别约束什么
Typeflag 表示条目类型,Mode 表示权限及模式位,Size 表示普通文件的逻辑大小。0750 的前导零表示八进制,也可以写成 0o750;十进制 750 是另一个值。目录执行位控制路径遍历,不能机械套用配置文件的 0640。
Go 的 fs.FileMode 把类型标记放在自己的高位,直接转换整个值并不等于 tar 的 Unix 模式编码。手工创建 Header 时,把类型放到 Typeflag,普通读写执行位放到 Mode。特殊位和链接需要单独策略;本例只写目录与普通文件。

处理步骤:给空目录写头,给文件写足字节
下例先在内存中完成归档,再排他创建输出文件,便于把条目错误和外层文件错误分开。它适合小归档;较大产物应流式写入独立临时文件,避免内存随包体积增长。将代码保存为 main.go 后,可在独立工作目录运行;已有 mode-demo.tar 时程序会拒绝覆盖。
package main
import (
"archive/tar"
"bytes"
"fmt"
"os"
)
func build() ([]byte, error) {
var buf bytes.Buffer
tw := tar.NewWriter(&buf)
entries := []struct {
name string
kind byte
mode int64
body []byte
}{
{"bundle/", tar.TypeDir, 0755, nil},
{"bundle/cache/", tar.TypeDir, 0750, nil},
{"bundle/settings.txt", tar.TypeReg, 0640, []byte("zone=lab\n")},
{"bundle/start.sh", tar.TypeReg, 0750,
[]byte("#!/bin/sh\n# 示例脚本只打印状态\nprintf 'ready\\n'\n")},
}
for _, e := range entries {
// 类型和权限分别设置;目录不携带文件体。
h := &tar.Header{Name: e.name, Typeflag: e.kind,
Mode: e.mode, Size: int64(len(e.body))}
if e.kind == tar.TypeDir { h.Size = 0 }
if err := tw.WriteHeader(h); err != nil {
return nil, fmt.Errorf("条目头 %s: %w", e.name, err)
}
if e.kind == tar.TypeReg {
if _, err := tw.Write(e.body); err != nil {
return nil, fmt.Errorf("文件体 %s: %w", e.name, err)
}
}
}
// 检查归档结束错误;tar.Close 不负责关闭底层文件。
if err := tw.Close(); err != nil { return nil, err }
return buf.Bytes(), nil
}
func main() {
data, err := build()
if err != nil { fmt.Fprintln(os.Stderr, err); os.Exit(1) }
// 排他创建,避免覆盖已有包;这里只演示小归档。
f, err := os.OpenFile("mode-demo.tar", os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0600)
if err != nil { fmt.Fprintln(os.Stderr, err); os.Exit(1) }
_, writeErr := f.Write(data)
closeErr := f.Close()
if writeErr != nil || closeErr != nil {
fmt.Fprintln(os.Stderr, "输出失败,请隔离未完成的 mode-demo.tar", writeErr, closeErr)
os.Exit(1)
}
fmt.Println("已写入 mode-demo.tar")
}
两个目录都有独立头部,cache 即使为空也有条目。目录不写文件体;普通文件先写头再写对应内容。含中文的数据也要按 UTF-8 字节数声明,示例对 []byte 求长度,而非按字符数估算。
写入超过声明大小会返回 ErrWriteTooLong;不足则在后续写头或结束归档时暴露错误。必须处理 tar.Writer.Close 的返回值,不能让被忽略的 defer 吞掉归档结束错误。tar.Close 完成填充和尾部,并不代替底层文件 Close。若再组合 gzip,应先结束 tar,再结束 gzip,最后关闭文件,各层错误都要处理。
真实文件的模式转换,需要明确保留策略
从文件信息创建头部可用 FileInfoHeader。它生成的 Name 通常只有基名,目录会加斜杠;需要保留 bundle/ 下的结构时,应设置自己的归档内名称。下列为函数内部片段,fi 和 tw 由调用方提供:
// fi 为已确认的普通文件信息,tw 为调用方创建的 tar.Writer。
h, err := tar.FileInfoHeader(fi, "")
if err != nil { return err }
h.Name = "bundle/settings.txt" // 设置归档内相对路径,避免只留下基名。
h.Mode = int64(fi.Mode().Perm()) // 本策略仅保留普通权限,舍弃特殊位。
if err := tw.WriteHeader(h); err != nil { return err }
这里主动用 Perm 只保留普通九个权限位,特殊模式位会被舍弃。如果要求保留 setuid、setgid 或 sticky,不能把 Perm 当成完整保留所有模式;FileInfoHeader 本身提供类型及模式映射,是否覆盖应服从交付规则。
片段只适合已确认的普通文件。符号链接应把实际链接目标传给 FileInfoHeader 的第二个参数,不能传空字符串后继续当作普通文件处理。源文件在读取元数据后还可能变化,生产任务应使用稳定构建产物或快照;读取长度不一致时终止本包,不把半成品交给下游。
失败回退:隔离新包,保留旧交付物
不要直接截断正在使用的旧归档。使用独立临时文件名写入新包,全部写入和关闭成功后,再进入交付系统已有的切换环节。任何错误都保留旧版本,隔离未完成文件并记录条目名和失败阶段。文件已经存在,并不代表打包成功。
完整示例采用 O_EXCL 拒绝覆盖旧文件。若输出失败,操作者先确认 mode-demo.tar 属于本次未完成产物,再做清理。实际大包可沿用这个回退原则,同时为每次构建记录独立产物名,避免误删其他任务输出。

交付确认与复盘项
记录条目名、类型、八进制模式、声明大小、写入错误及关闭错误,有助于把字段错误、源文件变化和输出失败区分开。解包后的权限还受解包工具、目标文件系统及运行环境影响,不能仅凭 Header.Mode 承诺跨平台完全相同。
- 空目录在条目清单中独立出现,不只统计非空文件。
- 目录、配置与脚本采用不同权限策略,避免全包统一放宽。
- 归档内路径使用预期的相对名称,不把不受约束的外部路径直接写入。
- 只有完整写入与各层关闭成功才报告产物完成,失败时保留旧包。
目录名一定要有尾斜杠吗?显式 TypeDir 已经表达目录类型,尾斜杠是清晰的命名约定;不要依赖零值 Typeflag 的隐式推断。tar 会自动压缩吗?不会,本例是归档,压缩需另外组合 gzip 等写入器。Header.Mode 和 OpenFile 的 0600 一样吗?前者属于归档内条目,后者属于外层 mode-demo.tar,不能互相替代。
文件模式接口参考:https://pkg.go.dev/io/fs#FileMode。
Go log/slog.NewLogLogger 怎样适配旧式 Logger 接口
- 上一篇
- Go log/slog.NewLogLogger 怎样适配旧式 Logger 接口
- 下一篇
- Go image/png 怎样控制编码器压缩级别
-
- Golang · Go教程 | 1小时前 | go · 文件描述符 ·
- Go os/exec.Cmd.ExtraFiles 怎样把已打开文件传给子进程
- 148浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go strconv.ParseBool 怎样处理业务布尔值
- 394浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go strconv.Quote 怎样生成可复制的字符串字面量
- 263浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go encoding/hex 怎样复用目标缓冲区编码
- 198浏览 收藏
-
- Golang · Go教程 | 1小时前 | 标准库 · go · CRC32C hash/crc32 crc32.Table
- Go hash/crc32 怎样选择校验表
- 204浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go image/color 怎样在 RGBA 与 NRGBA 间转换
- 359浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go crypto/sha512 怎样计算文件摘要
- 128浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go image/jpeg 怎样选择质量参数
- 186浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go image/png 怎样控制编码器压缩级别
- 490浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go log/slog.NewLogLogger 怎样适配旧式 Logger 接口
- 433浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go io.LimitReader 怎样给流式输入设上限
- 145浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 847次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 850次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 931次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 905次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 733次使用
-
- Java 性能优化上线清单:从定位、改造到灰度发布
- 2026-06-11 860浏览
-
- Spring Boot 压测验证:Gatling、JMeter 与性能回归门禁
- 2026-06-11 843浏览
-
- Java NMT 非堆内存排查:Direct Buffer、线程栈与 Metaspace 分析
- 2026-06-11 826浏览
-
- Spring Boot 容器内存优化:JVM 堆、非堆与 MaxRAMPercentage
- 2026-06-11 809浏览
-
- Tomcat 连接与线程参数调优:maxThreads、acceptCount 与 KeepAlive
- 2026-06-11 792浏览

