设想:单个 1g CSV.gz 正在写入 FTP 文件夹。与此同时,我的客户端计算机通过 sFTP 连接到该文件夹并尝试将其拉下。
问:获取该文件后,无论我在客户端获得什么明显的长度,都可以gzip -t
检测到部分文件并使其失败,无论截断发生在哪里?
我认为当片段突然结束时,解压缩或 -t'esting 将在 99% 的可能截断点上出错,但是 gz 结构是否具有干净的切割点,gzip 会在其中意外报告成功?
不在桌面上的缓解措施(因为如果其中之一正在发挥作用,我就不需要问上述问题。)
- 通过另一个网络请求获取文件长度或md5。
- 通过 FTP 轮询文件长度并不是很好,因为服务器可能会偶尔将块写入 zip 流。在批处理作业关闭文件句柄之前,如果将其误认为是完整的数据集,对我的分析来说将是致命的。
- 通过批处理作业给出最终文件长度或散列,就不再需要这个问题,但这给团队带来了实施负担,而团队(就这个问题而言)可能不存在。
- 我们无法通过安排一天中不同时间的读/写来避免竞争。
- 服务器未使用原子移动操作。
- 我不知道 CSV 行/列数;每个快照和每个集成都会发生变化。对于这个问题,也可以说被 gzip 压缩的文件是一个不透明的二进制 blob。
- 游戏中没有 client=>sFTP 网络错误。 (这些被捕获并处理;我关心的是读取在服务器的批处理作业期间仍然偶尔写入的文件。)
- 使用 RESTful API 代替 sFTP。
没有找到现有的SO
几个SO触及处理截断,但与需要在任何问题上可靠地使整个工作流程失败相比,处于有损可接受的环境中。 (我在医疗数据环境中进行计算,因此我宁愿让服务器停止并着火,也不愿传播错误的统计数据。)
- gzip:意外的文件结尾 - 如何读取文件恰恰相反——他们希望抑制 EOF 错误,因为这对他们的用例来说不是问题
- 为什么使用 gzip 时我的脚本中出现意外的文件结尾?只是 posix 流结尾有意插入,
head
并且不涵盖“是否有可能误报?” - 管道输出时 zcat / gzip 错误 非常接近,但不会问“我保证会收到此错误吗?”
- 合并可能被截断的 gzip 日志文件也很接近,因为它处理来自终止的批处理作业的部分文件,但仍然是抛出一些不可读的行,而不是保证错误。
答案1
gzip 格式的文件包含压缩数据的长度和未压缩数据的长度。然而,这是一种古老的格式,长度字段只有 32 位,因此现在它们被解释为长度模 2^32(即 4 GiB)。解压前,gzip
检查压缩数据的校验和是否正确。解压后,gzip
检查解压数据的校验和是否正确,以及解压数据的大小是否正确模2^32。
因此,如果压缩数据的大小(或解压缩数据的大小)小于 4 GiB,gzip 保证检测到截断的输入。但是,对于任意大小的文件,我看不出有任何理由说明这些检查就足够了。如果输入不是故意设计的,并且其长度以 4 GiB 为模均匀分布,则压缩长度和校验和匹配的可能性只有 1/2^64,此外,如果文件在多字节序列的中间或者未压缩数据的长度不匹配。 (这并不一定会将机会减少到 1/2^96,因为压缩长度模 2^32 和未压缩长度模 2^32 是相关的。)因此,只有很小的机会出现未检测到的错误,但它不是零,我确信它可能是故意制作的。
请注意,此分析仅适用于 gzip 压缩文件由单个流组成的情况。gunzip
可以解压缩由多个串联流组成的文件,并且无法检测文件是否包含有效的流序列,但需要更多的流。但是,您的生产链可能不会生成多流文件:gzip
它本身不会生成,您必须手动连接多个运行的输出,或者使用其他工具(pkzip?)。
服务器未使用原子移动操作。
不幸的是,我认为没有一种完全可靠的方法来检测错误,而无需该方法或在服务器完成写入后计算的外部元数据(长度或加密校验和)。