登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  Golang >  Go教程

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 位字段。

Go archive/zip FileHeader 32 位与 64 位大小字段的静态结构图
图1:FileHeader 的大小字段、ZIP64 兼容标记与 UncompressedSize64 之间的静态关系;这是说明图,不是运行截图。

因此,判断“这个条目解压后有多大”时,最小规则可以写成:

字段含义使用建议
CompressedSize64压缩后大小用于估算归档读取或存储占用
UncompressedSize64解压后大小用于解压前配额、内存和落盘边界
UncompressedSize32 位兼容字段只适合兼容旧逻辑,不作为通用首选

从 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。

Go ZIP 元数据读取与解压前大小策略的静态模块关系图
图2:ZIP 元数据读取、大小配额和内容流之间的静态边界;这是结果说明图,不是执行证据。

用最小清单排查读取结果

  1. 大小为零:先确认条目是否真的是空文件或目录。目录名通常以斜杠结尾,不能只靠大小判断文件类型。
  2. 32 位字段很大:看到 0xffffffff 时不要当成真实大小,改看 UncompressedSize64。
  3. 打开内容失败:元数据能读到不等于压缩流一定能成功解码,分别记录 File.Open 和后续读取错误。
  4. 归档文件没有及时释放:zip.OpenReader 返回的 ReadCloser 要在同一函数中安排 defer reader.Close()。
  5. 总量限制失效:不要只限制单个条目;批量导入时还要累计已接受的 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、读取和关闭依然可能返回错误。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>