gzbuffer
在缓冲区存在前选择请求大小。
完整章节与共同规则 ↗2425ced89b926581 · 对应提交的原文 ↗先看本函数的前置条件和返回结果;可展开下方共同规则,查看整组接口的缓冲区与所有权要求。
在缓冲区存在前选择请求大小。
int ZEXPORT gzbuffer(gzFile file, unsigned size);
定义域 受限定义域:活跃句柄;完整无符号 size 范围。
效果: 有状态缓冲配置,不分配缓冲区。
前置条件 活跃读取或写入句柄满足通用要求。
返回与保证 缓冲区尚未分配且 size < 2^31 时,返回 0,记录 max(size, 8)。
读取句柄后续需要输入缓冲区及双倍大小的输出缓冲区;
写入句柄需要双倍大小的输入缓冲区,gzip 写入还需要输出缓冲区。
错误与边缘情形: NULL、缓冲区已分配、模式错误或 size >= 2^31 时返回 -1,
不改变请求。小大小被提升至八,而不是二。请求成功不保证后续分配成功。
不但要在普通 I/O 前调用,也应在 gzdirect 或字节回退前调用。
本组共同前提与范围
使用 gzFile 句柄进行带缓冲的 gzip 文件 I/O。打开时取得文件描述符和私有状态;
数据操作按需初始化缓冲区和编解码器状态;即使最终 I/O 失败,关闭也会释放句柄。
读取还可接受透明的未压缩输入:文件中的字节不经解压,直接作为结果交付。
| 任务 | 入口 |
|---|---|
| 打开或配置 | 打开路径、打开描述符、缓冲区大小、压缩参数 |
| 读取 | 字节、数据项、字符、回退字节、行 |
| 写入 | 字节、数据项、字符、字符串、格式化文本、刷新 |
| 位置 | 定位、回到起点、未压缩位置、文件偏移 |
| 查询或清除状态 | 文件末尾、透明模式、错误、清除错误 |
| 关闭 | 任意模式、读取句柄、写入句柄 |
本页按固定版本源码和 zlib.h 组织接口契约。各条目明确列出调用范围,
对应的完整执行要求见已登记公开目标,当前证据见进度。
超出聚焦前提只表示本契约不作保证,不自动等于 C 未定义行为(UB),也不保证一定返回错误码。
通用句柄条件
先分清两种位置。逻辑位置以未压缩字节计数;普通读写按已消费或接受的数量推进,定位还可以登记尚未执行的前移。底层文件另有物理偏移,它以文件中的字节计数。gztell 查询前者,gzoffset 查询后者。库会预读和缓冲,因此两个值通常不同;单次压缩率也不能用来换算它们。
例如,没有额外定位或字节回退时,读取句柄已向应用交付 1000 个解压字节,逻辑位置就是 1000;为了完成这些输出,底层可能已预读更靠后的压缩字节。相反,写入成功表示库接受了输入,不能据此推断这些字节已全部写入描述符。
后面的参数沿用这套单位:len 和缓冲区配置 size 按字节计;数据项接口中的 size 是每项字节数,nitems 是项数,总请求为 size * nitems 字节。offset 是有符号的未压缩字节位移;whence 指定从起点(SEEK_SET)还是当前位置(SEEK_CUR)计算。INT_MAX 是本构建中有符号 int 能表示的最大值,即 2^31 - 1。
本页把可直接重试的非阻塞停顿与其他已记录的“硬错误”分开描述。这个区别说明本次调用怎样返回;它不免除错误后的状态、重试和清理要求。
本页使用默认 x86_64 Linux 构建。int 和 unsigned 为 32 位。
long、z_off_t、z_off64_t 和 z_size_t 为 64 位。大文件声明已启用。
这里普通入口和 *64 入口的偏移范围相同。其他配置需要单独契约。
gzopen_w 仅适用于 Windows,下文另行限定其范围。
受限定义域指满足下列通用要求的普通用法:
- 非 NULL 句柄由成功打开返回、仍存活且尚未关闭。串行使用它,调用者不修改其私有状态。
- 读取或写入句柄具有入口指定的访问模式。NULL 和错误模式的拒绝情形分别说明。 已失效或任意指针不在本定义域内;检查模式字段不等于验证指针。
- 缓冲区覆盖请求的可读或可写范围,并与句柄拥有的内存分离。 字符串具有可读的终止 NUL。调用者保留这些对象的所有权。
- 位置运算和请求范围能由指定 C 类型表示。下述契约仍包括显式的超大请求和乘法溢出拒绝。
- 描述符在关闭前属于句柄。调用期间,没有其他操作改变其数据或位置。 操作系统失败和分配失败仍可能发生;成功打开不保证后续 I/O 成功。
每个入口均带定义域标签。“完整标量范围”仅在上述指针和生存期要求下, 适用于所指明的标量参数。文档中的限制不免除已知失败路径的义务。 特别地,部分读取错误和字节回退形成的负位置仍属于未改变的公开目标。
效果。 读、写、打开、定位、控制和关闭均为有状态操作,包括没有调用者输出缓冲区的操作。
位置查询(gztell、gzoffset)和文件末尾查询(gzeof)读取状态;gzerror 还可能写入可选错误码输出。
gzdirect 可读取文件并分配内存,因此也是有状态操作。
stateDiagram-v2
state "新建句柄" as Fresh
state "已开始数据处理" as Active
state "已关闭" as Closed
[*] --> Fresh: 成功打开
Fresh --> Active: 首次 I/O 或格式检查
Active --> Active: 读、写、定位、控制
Fresh --> Closed: 关闭
Active --> Closed: 关闭,包括最终 I/O 失败
Closed --> [*]
格式与缓冲。 打开时不对载荷执行 I/O。缓冲区和编解码器状态按需分配, 默认请求的缓冲区大小为 8192 字节。请求大小是配置量,实际内部存储还包括下述双倍缓冲区和编解码器状态。首次使用或后续解压期间都可能分配失败。 即使最终 I/O 失败,关闭也释放拥有的分配。
普通读取句柄根据合理的四字节头部识别 gzip;否则原样返回输入。
空输入属于透明输入。非阻塞输入在获得四字节前停顿时,检测保持等待。
一个 gzip 成员是一段带有自身头部、压缩数据和尾部校验信息的完整流;一个文件可以顺序放置多个成员。读取输出按顺序拼接各成员的未压缩数据。若尝试解码下一个成员时,在格式错误前未产生输出,
则忽略尾随的非成员数据。G 要求 gzip;T 选择透明输出,不能用于读取。
读取结果。 读取按已消费字节数推进未压缩位置,包括最终的部分数据项。
已缓冲字节可能在已记录错误被报告之前返回。gzeof 表示曾尝试读取可用数据之后的内容,
而不只是已交付最后一个字节。gzerror 区分 EOF、损坏(Z_DATA_ERROR)、
截断(Z_BUF_ERROR)、分配失败(Z_MEM_ERROR)和系统失败(Z_ERRNO)。
零长度读取不消费输入,也不执行待处理定位。
写入结果。 成功表示句柄已接受输入;数据仍可能在缓冲区内。 后续刷新或关闭仍可能失败。硬错误可能在消费一个前缀后返回失败; 仅凭返回值不总能确定重试偏移。非阻塞停顿则可能返回至今已消费的数量。
错误通常持续到被清除。已记录的非阻塞停顿允许下次数据 I/O 重试。
定位和回到起点仍拒绝该已记录的 Z_ERRNO。构造错误消息本身可能失败,
并将错误码改为 Z_MEM_ERROR。errno 只对关联的系统失败有意义,
不能普遍解释每个失败的 API 调用。
源码为 gzlib.c、gzread.c、
gzwrite.c、gzclose.c 和
zlib.h。抽象契约位于 Api/Gz.lean。
具体目标位于 GzOpen、
GzRead、GzWrite、
GzControl 和
GzClose。翻译在 ZlibF/Zlib/ 中保留 C 名称。
形式化约定
ZlibF.Spec.Public.Goal.gzbuffer
证明状态:已登记证明 · 证明记录与剩余工作
/-- `int gzbuffer(gzFile file, unsigned size)`.
The current source clamps to eight bytes. It refuses initialized buffers and doubled-size overflow. -/
def Goal.gzbuffer : Prop :=
(∀ h size, C.run (Zlib.Gzlib.gzbuffer none size) h = .ok (-1, h)) ∧
(∀ h i s size, h.gzstates i = some s →
C.run (Zlib.Gzlib.gzbuffer (some (.in_gzstate_x i)) size) h =
if (s.mode ≠ GZ_READ ∧ s.mode ≠ GZ_WRITE) ∨ s.size ≠ 0 ∨ 2 ^ 31 ≤ size.toNat then
.ok (-1, h)
else .ok (0, putGz h i { s with want := UInt32.ofNat (max size.toNat 8) }))相关定义与源码 ↗