Go 的 archive/zip 包默认将文件修改时间设为 Unix 时间零点(1979-11-30 00:00),可通过 os.FileInfo 和 zip.FileInfoHeader 显式设置为当前时间。
go 的 archive/zip 包默认将 zip 条目中的修改时间(modified time)设为 unix 时间起点(即 1979-11-30 00:00 utc,对应 dos 时间戳的 0 值),而非真实创建时间。这会导致解压后文件时间异常,影响构建可重现性或时间敏感逻辑。解决方法是利用 zip.fileinfoheader 函数——它基于 os.fileinfo 构建带正确 modtime 的 *zip.fileheader,再手动覆盖其 modtime 字段为 time.now()。
要为 ZIP 中的新文件条目设置当前时间,请按以下步骤操作:
- 创建一个符合 os.FileInfo 接口的临时对象(如使用 fakeFileInfo 结构体);
- 调用 zip.FileInfoHeader 获取初始 *zip.FileHeader;
- 显式设置 header.ModTime = time.Now();
- 使用 zipWriter.CreateHeader(header) 写入条目。
以下是完整示例代码:
package main
import (
"archive/zip"
"io"
"os"
"time"
)
// fakeFileInfo 实现 os.FileInfo 接口,仅用于生成 FileHeader
type fakeFileInfo struct {
name string
size int64
}
func (f fakeFileInfo) Name() string { return f.name }
func (f fakeFileInfo) Size() int64 { return f.size }
func (f fakeFileInfo) Mode() os.FileMode { return 0644 }
func (f fakeFileInfo) ModTime() time.Time { return time.Now() } // 关键:此处设为 now
func (f fakeFileInfo) IsDir() bool { return false }
func (f fakeFileInfo) Sys() interface{} { return nil }
func main() {
f, _ := os.Create("example.zip")
defer f.Close()
zw := zip.NewWriter(f)
defer zw.Close()
// 创建自定义 FileInfo(ModTime 为当前时间)
fi := fakeFileInfo{name: "hello.txt", size: 12}
header, _ := zip.FileInfoHeader(fi)
header.Method = zip.Deflate // 可选:启用压缩
// 创建文件条目并写入内容
w, _ := zw.CreateHeader(header)
io.WriteString(w, "Hello, World!")
zw.Close()
}
⚠️ 注意事项:
- zip.FileInfoHeader 本身会读取传入 fi.ModTime(),因此确保你的 FileInfo 实现返回期望时间(如 time.Now());
- 若从磁盘读取真实文件,可直接使用 os.Stat() 获取其 os.FileInfo,再调用 zip.FileInfoHeader ——但需注意该方式继承原文件时间;若需强制设为当前时间,仍需手动赋值 header.ModTime = time.Now();
- ZIP 时间精度为 2 秒(DOS 时间格式限制),time.Now() 会被自动向下舍入到最近的 2 秒边界,属正常行为,无需额外处理。
通过此方法,可确保 ZIP 文件内每个条目的修改时间准确反映打包时刻,提升归档可靠性与可追溯性。











