Python如何删除JPG文件FFD9结束标记后追加的自定义数据
问题根源
你的删除函数存在3个核心问题,直接触发报错的是IO对象操作逻辑错误:
- 第二个
with块使用ab(追加写入)模式打开文件,此时fimg是IO写入流对象,不是支持下标切片的字节序列,无法执行fimg[0:end_i]操作,这就是TypeError: '_io.BufferedWriter' object is not subscriptable报错的直接来源。 ab模式下所有写入操作默认会拼接到文件末尾,无法实现截断文件、删除末尾内容的效果。- 直接用
index()找第一个匹配的FFD9字节逻辑有缺陷:带EXIF缩略图的JPG文件中,缩略图的结束标记也为FFD9,会出现在主图结束标记之前,此时找第一个FFD9会把文件截断到缩略图位置,导致主图损坏。合法JPG的文件结束标记(EOI)一定是整个文件中最后一个FFD9序列。 - 冗余逻辑:你已经把全量文件内容读入
content变量,完全不需要调用seek计算位置。
正确实现
简易版(适配小尺寸JPG)
逻辑直观,读取全量内容截断后直接覆盖写回,适合几MB到几十MB的常规图片:
def erase_data_in_img_fct(img_jpg_file_path: str) -> None: with open(img_jpg_file_path, 'rb') as fimg: content = fimg.read() # 从后向前查找最后一个FFD9标记,避免误判前置的缩略图结束标记 eoi_pos = content.rfind(bytes.fromhex('FFD9')) if eoi_pos == -1: raise ValueError("文件不是合法JPG,未找到结束标记FFD9") # FFD9本身占2字节,截断到标记结束位置即可 valid_content = content[:eoi_pos + 2] # 以二进制覆盖模式写回截断后的内容 with open(img_jpg_file_path, 'wb') as fimg: fimg.write(valid_content)
内存优化版(适配大尺寸JPG)
不需要把整个文件读入内存,直接在文件上定位标记后调用截断方法,适合几百MB以上的大尺寸原图:
def erase_data_in_img_fct(img_jpg_file_path: str) -> None: # 以可读可写二进制模式打开,不自动截断原文件 with open(img_jpg_file_path, 'r+b') as fimg: fimg.seek(0, 2) # 先跳转到文件末尾 file_size = fimg.tell() eoi_pos = -1 # 仅从文件末尾向前扫描最多100KB范围,足够覆盖常规追加内容长度,避免扫描全文件 max_scan_len = min(file_size, 1024 * 100) for offset in range(file_size, file_size - max_scan_len, -1): fimg.seek(offset - 2) if fimg.read(2) == bytes.fromhex('FFD9'): eoi_pos = offset - 2 break if eoi_pos == -1: raise ValueError("扫描范围内未找到JPG结束标记,文件可能已损坏") # 直接截断文件到标记结束位置,后续追加的内容会被清除 fimg.truncate(eoi_pos + 2)
效果验证
JPG解析器读取到文件结束标记FFD9后就会停止解析,后续追加的内容不会被识别为图片数据,这也是你之前追加字符串后图片能正常打开的原因。调用上述删除函数后,文件大小会恢复到追加前的原始值,图片可正常打开无损坏。
内容的提问来源于stack exchange,提问作者X0-user-0X
相关产品推荐
相关产品推荐

