Go archive/zip.FileHeader.UncompressedSize64 怎样读取条目原始大小
来源:17golang原创
时间:2026-11-06 14:37:41 176浏览 收藏
读取 ZIP 条目的“原始大小”时,直接看 zip.FileHeader.UncompressedSize64。它表示条目解压后的字节数,类型是 uint64,不需要先打开内容流;普通 ZIP 中它通常与旧的 UncompressedSize 数值相同,但 ZIP64 条目必须以 64 位字段为准。
官方地址:https://pkg.go.dev/archive/zip#FileHeader
如果你的代码要在解压前做容量、内存或业务配额判断,就读取UncompressedSize64,不要把UncompressedSize当成所有 ZIP 条目的完整大小来源。
先把两个 size 字段看懂
FileHeader 同时保留了 32 位和 64 位大小字段,是为了兼容旧的 ZIP 格式读取逻辑。压缩大小看 CompressedSize64,解压后的原始大小看 UncompressedSize64。两者不要混用:前者更接近归档文件实际占用的压缩数据规模,后者才适合估算解压后需要处理的数据量。
官方文档对 ZIP64 的说明很关键:64 位字段总是包含正确值;普通归档中 32 位和 64 位字段一般相同;当条目需要 ZIP64 时,32 位字段可能是 0xffffffff,这时必须使用 64 位字段。

因此,判断“这个条目解压后有多大”时,最小规则可以写成:
| 字段 | 含义 | 使用建议 |
|---|---|---|
CompressedSize64 | 压缩后大小 | 用于估算归档读取或存储占用 |
UncompressedSize64 | 解压后大小 | 用于解压前配额、内存和落盘边界 |
UncompressedSize | 32 位兼容字段 | 只适合兼容旧逻辑,不作为通用首选 |
从 Reader.File 读取条目元数据
遍历 Reader.File 时,每一个 *zip.File 都嵌入了一个 FileHeader。所以只读条目大小不需要调用 File.Open,也不会因为查看元数据而启动解压流。
package main
import (
"archive/zip"
"fmt"
"log"
)
func main() {
// 只读取 ZIP 中央目录和条目元数据,不打开条目内容流。
reader, err := zip.OpenReader("assets.zip")
if err != nil {
log.Fatal(err)
}
// ReadCloser 持有归档文件资源,函数结束前要关闭。
defer reader.Close()
for _, file := range reader.File {
// FileHeader 嵌入在 zip.File 中,64 位字段适用于普通 ZIP 和 ZIP64。
rawSize := file.UncompressedSize64
packedSize := file.CompressedSize64
fmt.Printf("%s: raw=%d bytes, packed=%d bytes\\n", file.Name, rawSize, packedSize)
}
}
这个例子中的 rawSize 是条目内容解压后的字节数,packedSize 是压缩后的字节数。两者都是元数据读取结果;它们并不代表已经把文件内容读入内存。
处理 ZIP64 与旧字段哨兵值
最容易出现误判的地方,是把 uint32 的最大值当成真实大小。对需要 ZIP64 的条目,UncompressedSize 可能为 0xffffffff,它表达的是“32 位字段放不下,请看 64 位字段”,而不是条目恰好有 4 GiB 减 1 字节。
package main
import (
"archive/zip"
"fmt"
)
func displaySize(file *zip.File) {
// 业务展示和配额判断统一使用 64 位未压缩大小。
rawSize := file.UncompressedSize64
// 仅用于说明兼容字段,不能据此覆盖 rawSize。
legacySize := file.UncompressedSize
fmt.Printf("%s: size64=%d, legacy=%d\\n", file.Name, rawSize, legacySize)
}
新代码通常不需要自己写“如果旧字段等于 0xffffffff 就切换”的分支,因为标准库已经把正确的 64 位值放在 UncompressedSize64 中。手动兼容旧字段时,也要把这个哨兵值当作切换信号,而不是参与加法、排序或容量计算。
把大小放进解压前的安全边界
读取大小的价值不只是打印日志,更重要的是在真正打开内容流前做决策。例如,服务只允许处理 256 MiB 以内的单个条目,就可以先比较 UncompressedSize64,超限时跳过 File.Open。这里的单位换算要保持在 uint64 范围内,避免先转成有符号整数导致大值溢出。
package main
import (
"archive/zip"
"fmt"
"io"
)
const maxEntrySize uint64 = 256 maxEntrySize {
return fmt.Errorf("条目 %q 解压后超过大小上限", file.Name)
}
// Open 返回的流仍然要关闭,大小判断不能替代资源清理。
stream, err := file.Open()
if err != nil {
return err
}
defer stream.Close()
// 示例只读取通过元数据门槛的内容;真实业务可替换为受限写入器。
_, err = io.Copy(io.Discard, stream)
return err
}
大小检查可以减少明显的资源风险,但它不是完整的解压安全策略。压缩流仍可能在读取时报告格式错误或校验错误,业务还应处理 Open、读取和关闭阶段的错误;如果需要限制总量,还要在多个条目之间累计已接受的 UncompressedSize64。

用最小清单排查读取结果
- 大小为零:先确认条目是否真的是空文件或目录。目录名通常以斜杠结尾,不能只靠大小判断文件类型。
- 32 位字段很大:看到
0xffffffff时不要当成真实大小,改看UncompressedSize64。 - 打开内容失败:元数据能读到不等于压缩流一定能成功解码,分别记录
File.Open和后续读取错误。 - 归档文件没有及时释放:
zip.OpenReader返回的ReadCloser要在同一函数中安排defer reader.Close()。 - 总量限制失效:不要只限制单个条目;批量导入时还要累计已接受的 64 位大小,并在累计前检查加法溢出。
可以把排查分成三层:先确认 Reader.File 是否拿到了条目,再确认 FileHeader.UncompressedSize64 是否符合 ZIP64 语义,最后才检查 File.Open 和内容读取。这样不会把“元数据读取成功”和“解压成功”混为一个结果。
总结
Go archive/zip.FileHeader.UncompressedSize64 怎样读取条目原始大小 的核心答案只有一句:从 *zip.File 直接读取 UncompressedSize64,把它作为解压后大小的首选来源。普通 ZIP 中它通常和 32 位字段相同,ZIP64 条目中则必须依赖它;在打开内容流前先用这个值做单条目和总量边界,代码会更容易控制内存、落盘和处理时间。
相关问题
UncompressedSize64 是压缩包文件占用的大小吗?不是。它是条目解压后的大小;压缩包中更接近实际压缩数据占用的是 CompressedSize64。
读取大小前需要调用 File.Open 吗?不需要。大小在 FileHeader 元数据中,遍历 Reader.File 就能读取。
看到 0xffffffff 应该怎么办?把它视为 32 位字段无法表达完整值的哨兵,使用 UncompressedSize64,不要把它当成实际字节数。
大小检查后还要处理读取错误吗?要。大小检查只能决定是否允许继续,File.Open、读取和关闭依然可能返回错误。
-
860 收藏
-
843 收藏
-
826 收藏
-
809 收藏
-
792 收藏
-
475 收藏
-
228 收藏
-
399 收藏
-
298 收藏
-
400 收藏
-
186 收藏
-
378 收藏
-
256 收藏
-
492 收藏
-
417 收藏
-
113 收藏
-
170 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习