如何用Python从application/octet-stream类型的疑似Zip文件恢复数据?
数据恢复可行性分析与编程方案
问题原因分析
你得到的application/octet-stream类型文件,大概率是压缩过程异常中断、工具故障导致的损坏文件——要么是未生成正确压缩结构的残次品,要么是源文件数据直接被拼接成了一个无索引的大文件(因为大小和源文件夹一致,完全没压缩的可能性很高)。
编程恢复的可行路径
1. 先检测文件真实结构
首先通过文件头签名判断文件本质,不同格式有固定的开头字节:
- ZIP压缩包:
50 4B 03 04 - 7z压缩包:
37 7A BC AF 27 1C - RAR压缩包:
52 61 72 21 1A 07 00 - JPG图片:
FF D8 FF - PDF文档:
25 50 44 46(即%PDF) - DOCX/XLSX:
50 4B 03 04(和ZIP一致,因为是压缩格式)
用Python脚本读取文件头验证:
with open("backup.zip", "rb") as f: # 读取前8字节转十六进制 header_hex = f.read(8).hex().upper() print(f"文件头十六进制: {header_hex}")
如果检测到对应压缩格式的签名,说明是扩展名错误或损坏的压缩包;如果是图片/文档的签名,说明源文件被直接拼接了。
2. 针对损坏压缩包的恢复
如果是ZIP格式损坏:
- 尝试用第三方库
ziprepair修复:from ziprepair import repair_zip # 复制原文件到backup_repaired.zip再操作 repair_result = repair_zip("backup.zip", "backup_repaired.zip") if repair_result.success: print("修复成功,尝试用zipfile读取修复后的文件") import zipfile with zipfile.ZipFile("backup_repaired.zip", "r") as zf: print(zf.namelist()) else: print(f"修复失败: {repair_result.error_message}") - 如果修复失败,可以手动定位ZIP的中央目录(位于文件末尾,签名
50 4B 05 06),提取目录信息后逐个恢复文件,但这个过程需要熟悉ZIP格式规范,实现起来较复杂。
3. 针对源文件拼接的恢复
如果文件是多个源文件直接拼接的(无压缩结构),可以通过扫描文件签名来分割提取:
以下是提取JPG和PDF的示例脚本:
import os # 定义要识别的文件类型签名 file_signatures = { ".jpg": b"\xFF\xD8\xFF", ".pdf": b"%PDF" } output_dir = "recovered_files" os.makedirs(output_dir, exist_ok=True) with open("backup.zip", "rb") as f: file_data = f.read() current_pos = 0 file_count = 0 while current_pos < len(file_data): # 遍历所有签名,查找匹配的位置 matched_ext = None match_pos = len(file_data) for ext, sig in file_signatures.items(): pos = file_data.find(sig, current_pos) if pos != -1 and pos < match_pos: match_pos = pos matched_ext = ext if matched_ext is None: # 没有找到更多签名,结束 break # 如果当前位置和匹配位置有间隔,跳过无效数据 if match_pos > current_pos: current_pos = match_pos # 查找下一个签名的位置,作为当前文件的结束 next_pos = len(file_data) for ext, sig in file_signatures.items(): pos = file_data.find(sig, current_pos + len(sig)) if pos != -1 and pos < next_pos: next_pos = pos # 提取当前文件数据 file_content = file_data[current_pos:next_pos] file_name = f"recovered_{file_count}{matched_ext}" with open(os.path.join(output_dir, file_name), "wb") as out_f: out_f.write(file_content) print(f"已提取: {file_name}") file_count += 1 current_pos = next_pos print(f"提取完成,共恢复{file_count}个文件")
注意:这种方法对无明显签名的纯文本文件效果差,且可能出现文件截断或合并的情况,需要手动验证恢复的文件完整性。
关键注意事项
- 绝对不要修改原始文件,所有操作都在复制的副本上进行,避免二次损坏。
- 50GB文件处理耗时较长,建议在性能较好的机器上运行脚本,且确保有足够的存储空间存放恢复的文件。
内容的提问来源于stack exchange,提问作者user19192927
相关产品推荐
相关产品推荐

