使用Python读取AWS S3中.gz文件报错Not a gzipped file的解决方法
解决S3读取.gz文件时的“Not a gzipped file”错误
错误原因分析
报错中的b'\xef\xbb'是UTF-8字节顺序标记(BOM)的前两个字节,说明你处理的文件存在以下情况之一:
- 文件本身不是真正的gzip压缩文件,只是被错误地加上了
.gz后缀,实际是带BOM的文本文件(比如XML) - 压缩前的原始文件带有UTF-8 BOM,压缩后BOM被保留在文件开头,导致gzip无法识别
处理步骤与代码修改
1. 先验证文件的真实格式
优先确认文件是否为有效gzip文件:
- 下载文件到本地,用7-Zip、
gzip -d等工具尝试解压,看是否能正常打开 - 在代码中通过gzip魔数验证:标准gzip文件开头是
b'\x1f\x8b',这比后缀名和Content-Type更可靠
2. 修正后的代码实现
下面的代码会先验证文件格式,处理可能的BOM问题,再进行解压:
import gzip import io job.file_bucket = 'upload-bucket' job.file_path = 'filepath/filename.gz' s3client = AwsS3Service.get_client(True) file_object = s3client.Object(job.file_bucket, job.file_path) # 获取完整文件内容(大文件建议流式处理,这里先以完整读取为例) response = file_object.get() file_content = response['Body'].read() content_type = response["ContentType"] job.cFilePath = f"{job.file_bucket}/{job.file_path}" # 验证gzip魔数,确认文件真实格式 is_valid_gzip = len(file_content) >= 2 and file_content[:2] == b'\x1f\x8b' # 结合格式验证、内容类型、后缀判断是否需要解压 if (content_type == 'application/x-gzip' or (content_type == 'binary/octet-stream' and job.cFilePath.endswith('.gz'))) and is_valid_gzip: # 检查并跳过UTF-8 BOM(如果存在) if file_content.startswith(b'\xef\xbb\xbf'): file_content = file_content[3:] # 完整BOM长度为3字节 elif file_content.startswith(b'\xef\xbb'): file_content = file_content[2:] # 处理不完整的BOM # 用BytesIO包装字节流,再通过gzip解压 with gzip.GzipFile(fileobj=io.BytesIO(file_content), mode='rb') as gz_file: xml_data = gz_file.read() else: # 不是有效gzip文件,直接按文本处理(兼容带BOM的XML) if file_content.startswith(b'\xef\xbb\xbf'): xml_data = file_content[3:].decode('utf-8') else: xml_data = file_content.decode('utf-8')
3. 关键修改点说明
- 魔数验证:避免仅依赖后缀名和Content-Type判断文件类型,这两个字段可能被错误设置
- BOM处理:如果文件开头存在BOM,先移除再解压,解决gzip无法识别的问题
- 字节流处理:用
io.BytesIO将S3返回的字节内容包装成类文件对象,替代gzip.open(后者更适合本地文件路径)
额外建议
- 排查文件上传流程:确认上传到S3的文件确实是通过gzip压缩生成的,而非手动修改后缀名
- 大文件优化:如果文件体积较大,建议采用流式读取+解压的方式,避免一次性加载所有内容到内存
内容的提问来源于stack exchange,提问作者Pranav Kokate
相关产品推荐
相关产品推荐

