阅读文本 / Reading text
本文使用合成样本演示处理方法。代码已通过隔离环境中的示例检查;这不代表对所有真实文件或产品效果的保证。处理重要文件前,请保留原件,并按文中的边界与验收项复核。
客户先后传来两份都叫
final.pdf
的文件,哪一份做了翻译?靠文件名回答这个问题很危险。同名文件可以内容不同,改过名字的文件也可能字节完全相同。内容哈希适合建立版本对应关系,但不应该被赋予它没有的含义。
为输入留下字节指纹
SHA-256 根据文件字节计算摘要。大文件可以分块读取,不必一次装入内存。哈希结果与分块大小无关;分块只是读取策略,不是文件身份的一部分。下面的内存流是合成样本,不包含真实文档。
用同内容、不同切块验证实现
import hashlib
from io import BytesIO
def digest(stream, chunk_size=65536):
if type(chunk_size) is not int or chunk_size <= 0:
raise ValueError("positive chunk size required")
h = hashlib.sha256()
while block := stream.read(chunk_size):
h.update(block)
return h.hexdigest()
raw = b"synthetic document version A\n"
a = digest(BytesIO(raw), 3)
assert a == digest(BytesIO(raw), 4096)
assert a == hashlib.sha256(raw).hexdigest()
assert a != digest(BytesIO(raw.replace(b"A", b"B")))
assert digest(BytesIO(b"")) == hashlib.sha256(b"").hexdigest()
try:
digest(BytesIO(raw), 0)
except ValueError:
pass
else:
raise AssertionError("zero chunk must be rejected")
函数从当前流位置读取。正式调用前应明确流是否位于开头,不能在解析器已经读过一部分后直接计算并称为“整份文件哈希”。最稳妥的方式是单独打开只读输入,或在可定位流上明确复位。
字节相同与内容相同有区别
情况
哈希可能怎样变化
如何解释
只改文件名
不变
名称不参与字节摘要
PDF 元数据被重写
改变
页面看起来相同也可能不同
重新保存压缩包
改变
压缩参数或时间戳可影响字节
翻译成另一语言
通常改变
输入输出应该分别记录
不要把哈希当权限凭证
知道一个文件摘要不代表有权下载它,也不代表拥有版权。跨租户去重还可能泄露“某个文件是否已存在”的信息。缓存命中之后仍需做访问控制,并把来源、租户和处理策略纳入业务记录。
翻译清单从这里开始
将文件送入
OmniDoc(产品入口)
前记录输入摘要,下载译稿后记录输出摘要,再关联语言与术语版本。这样同事说“结果不对”时,首先就能确定双方检查的是同一组文件,而不必围着多个
final
文件名猜测。
参考:
Python hashlib
。
- 1 -
更新于 2026-10-08