Python如何合并列表中多个远程json.gz文件为单个文件并打开
问题背景
我有一个存储json.gz文件HTTPS访问链接的列表。
温馨提示:出于隐私法规要求,下列链接均非真实文件地址,但文件结构与实际业务场景完全一致。
list_of_files = ['https://premera.saph.com/202011/json.gz', 'https://premera.saph.com/202011/json.gz']
我的目标是将所有这些json.gz文件合并为一个大容量的json.gz文件。之前参考过多个相关实现方案,始终没有找到完全适配当前场景的方案。
之前看到的Python读写gzip压缩JSON文件的方案给了我部分思路,但我当前场景的文件都是HTTP协议的远程资源,需要先拉取远程文件内容才能处理。
我最初写的测试代码如下:
import requests import gzip one_file = file[0] with open(one_file, 'rb') as f: serial = gzip.decompress(f.read())
运行代码后抛出如下报错:
OSError: [Errno 22] Invalid argument: 'https://premera.saph.com/202011/json.gz'
说明:上述代码中的HTTPS地址已因隐私要求做了替换,使用真实有效地址运行时也会出现相同报错。
报错原因
报错核心原因非常直接:Python内置的open()函数仅支持读取本地文件系统的文件,不支持直接传入HTTP/HTTPS链接读取远程资源,把URL当本地路径传入必然触发参数非法错误。
实现方案
不需要把所有远程文件全量下载到本地磁盘暂存,用流式处理的方式边拉取、边解压、边写入最终文件即可,内存占用低、处理效率高,具体步骤:
- 用
requests.get()发起请求拉取远程gzip文件,设置stream=True避免大文件一次性加载占满内存 - 直接把响应的二进制流对象传给
gzip.GzipFile做解压,不需要把文件存到本地 - 读取解压后的JSON内容,写入到新生成的gzip压缩文件中
- 遍历处理完所有链接后,就得到合并完成的json.gz文件
完整参考代码:
import gzip import requests # 远程文件列表 list_of_files = ['https://premera.saph.com/202011/json.gz', 'https://premera.saph.com/202011/json.gz'] # 合并后输出的文件路径 output_file = "merged_json_data.json.gz" with gzip.open(output_file, 'wb') as f_out: for file_url in list_of_files: # 拉取远程gzip流 resp = requests.get(file_url, stream=True) resp.raise_for_status() # 请求失败(比如403、404)直接抛错,避免无效处理 # 直接从响应流解压内容 with gzip.GzipFile(fileobj=resp.raw) as f_in: # 逐块复制解压后的内容到输出文件,块大小设为1MB平衡内存和速度,兼容全版本Python3 while True: chunk = f_in.read(1024 * 1024) if not chunk: break f_out.write(chunk)
补充说明
- 如果你的单个源文件体积特别大,上面的逐块读取逻辑是内存最优的,不会因为文件太大导致内存溢出
- 如果你需要校验JSON格式合法性,不要直接拼接二进制块,可以逐行读取JSON内容(适配JSON Lines格式,即每行一个独立JSON对象),校验后再写入,避免合并后的文件格式损坏
- 如果你的远程资源需要鉴权,给
requests.get()传入headers参数携带Cookie、Token等认证信息即可 - 如果源文件解压后是单个完整JSON数组/对象,直接复制二进制块的方式可能导致多个JSON结构拼接后格式错误,这种情况需要先加载JSON内容,合并数据结构后再统一序列化写入输出文件
内容的提问来源于stack exchange,提问作者Zane
相关产品推荐
相关产品推荐

