大日志按固定 1MB 切片上传,每片单独解码时最后几个字符是问号。合并回去看,原文件里那几个汉字正好跨在切口上。碰到这种情况,我一般先确认改动有没有真的生效。
原因不复杂,UTF-8 一个汉字占三字节,按字节数硬切会把三字节序列劈开,单独解码时后半段变成非法序列。解码器遇到不完整序列只能替换成 U+FFFD,信息就丢了。
「字节截断 UTF-8」相关的验证我通常做两遍,改完一次、隔天再看一次,确认不是临时生效。别只看报错的最后一行,往上看几行,真正的起因通常在上面。
size = 1024 * 1024
with open('app.log', 'rb') as f:
chunk = f.read(size)
cut = chunk.rfind(b'\n') + 1 or len(chunk)
part = chunk[:cut]
同类问题如果隔一段时间又出现,多半是某个定时任务或重启流程把改动冲掉了。
具体做法是,切分时向后找到最近的换行符再切 保证不劈开字符;必须按字节切就用 codecs 的 incremental decoder;每片带上起始字节偏移 合并时按偏移拼;校验合并结果和原文件 sha256 一致。
最后用这个标准收尾,每片单独 decode('utf-8') 不抛异常 合并后 sha256 和原文件相同。
