AWS S3 下载的 .gz 文件名具有误导性——S3 默认可能自动解压响应内容,导致实际保存的是原始 JSON 文本而非 GZIP 流,直接用 gzip.open() 会触发 BadGzipFile 异常。
aws s3 下载的 `.gz` 文件名具有误导性——s3 默认可能自动解压响应内容,导致实际保存的是原始 json 文本而非 gzip 流,直接用 `gzip.open()` 会触发 `badgzipfile` 异常。
当你在 Python 中遇到 BadGzipFile: Not a gzipped file (b'{\n') 错误,且错误头字节显示为 b'{ '(即典型的 JSON 开头),这几乎可以确定:该文件根本不是 GZIP 格式,而是一个纯文本 JSON 文件,只是被错误地保留了 .gz 后缀。
这个问题常见于通过 boto3 或浏览器直链从 AWS S3 下载对象时未显式设置 Content-Encoding: gzip 响应头,或 S3 Bucket 配置了自动解压缩(如启用了 S3 Object Lambda、CloudFront 压缩策略,或客户端请求头中包含 Accept-Encoding: gzip 导致服务端提前解压)。结果就是:你下载到本地的 example.gz 实际内容是明文 JSON,但扩展名仍为 .gz。
✅ 正确做法:先验证文件是否真实压缩,再选择读取方式:
import gzip
import json
def safe_read_gz_or_json(filepath):
"""安全读取:自动判断是 gzip 还是纯文本 JSON"""
try:
# 尝试以 gzip 方式读取(二进制模式检测魔数)
with gzip.open(filepath, 'rb') as f:
# 读取前 2 字节检查 gzip 魔数(0x1f 0x8b)
magic = f.read(2)
if magic != b'‹':
raise gzip.BadGzipFile("Missing gzip magic header")
# 若魔数正确,重置指针并完整读取
f.seek(0)
content = f.read()
return json.loads(content.decode('utf-8'))
except (gzip.BadGzipFile, UnicodeDecodeError):
# 回退:当作普通 UTF-8 JSON 文件读取
with open(filepath, 'r', encoding='utf-8') as f:
return json.load(f)
# 使用示例
data = safe_read_gz_or_json('example.gz')
print(data['domain']['name']) # 输出: myname
? 快速诊断技巧(命令行):
# 查看文件真实类型(Linux/macOS) file example.gz # ✅ 正常 gzip 文件输出:example.gz: gzip compressed data # ❌ 问题文件输出:example.gz: JSON data # 查看前 16 字节十六进制(确认是否含 1f 8b) xxd -l 16 example.gz # 若输出首两字节非 00000000: 1f8b ...,则不是 gzip
⚠️ 注意事项:
- 不要依赖文件扩展名判断格式,始终以文件内容(如魔数)为准;
- 在自动化流水线中(如 Airflow、Lambda),务必对 S3 下载逻辑显式设置 ResponseContentType 和禁用自动解压(例如 boto3.client.get_object(Bucket=..., Key=..., ResponseContentType='application/gzip') 并检查 response['ContentEncoding']);
- 若需确保下载压缩包,请在 S3 控制台或 put_object 时显式设置 ContentEncoding='gzip',并验证对象元数据;
- gzip.open(..., 'rt') 要求文件必须是有效 gzip 流;若误传明文,Python 3.8+ 会严格校验魔数并立即报错。
总之,面对 BadGzipFile + b'{ ',第一反应不是修复代码,而是验证文件真实性——99% 的情况是“名字骗人”,按普通 JSON 处理即可。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











