Python中URL大文件流式写入gzip文件的实现问题
流式下载并直接写入gzip文件的正确实现
嘿,我完全懂你想边下载边压缩、避免把大文件全塞进内存的需求!你的思路方向是对的,但问题出在直接把r.raw传给compressor.compress()——r.raw是一个流对象,不是可直接压缩的字节块,流式处理的核心是分块读取、分块压缩、即时写入,这样内存里永远只存一小块数据。
问题分析
你当前的代码尝试一次性压缩整个r.raw流,但zlib.compress()需要传入字节数据而非流对象。正确的姿势是逐块拉取下载内容,每拿到一块就压缩一块,立刻写入文件,彻底规避大内存占用。
方法一:用zlib手动控制流式压缩
下面是修正后的完整代码,我加了详细注释:
import requests import zlib url = "http://samplecsvs.s3.amazonaws.com/Sacramentorealestatetransactions.csv" save_file_path = "output.gz" # 开启流式下载模式 with requests.get(url, stream=True) as r: r.raise_for_status() # 先检查请求是否成功,避免无效流 # 初始化gzip格式的压缩对象(wbits加16是为了生成标准gzip头/尾,否则是deflate格式) compressor = zlib.compressobj(wbits=zlib.MAX_WBITS | 16) with open(save_file_path, 'wb') as f: # 分块读取内容,每次1MB(可根据内存情况调整块大小) for chunk in r.iter_content(chunk_size=1024*1024): if chunk: # 跳过可能的空块 # 压缩当前字节块 compressed_chunk = compressor.compress(chunk) # 立即写入压缩后的内容 f.write(compressed_chunk) # 最后刷新压缩器,把剩余未写入的压缩数据全部导出 f.write(compressor.flush())
方法二:用gzip模块更简洁实现
如果你不需要底层压缩的精细控制,Python自带的gzip模块已经封装了流式压缩逻辑,代码会更清爽:
import requests import gzip url = "http://samplecsvs.s3.amazonaws.com/Sacramentorealestatetransactions.csv" save_file_path = "output.gz" with requests.get(url, stream=True) as r: r.raise_for_status() # 用gzip.GzipFile直接以写模式打开,自动处理压缩逻辑 with gzip.GzipFile(save_file_path, 'wb') as f: # 逐块写入原始数据,gzip会自动完成压缩 for chunk in r.iter_content(chunk_size=1024*1024): if chunk: f.write(chunk)
这种方式不需要手动管理压缩对象,gzip模块会帮你处理所有压缩细节,代码可读性更高。
关键注意点
- 必须用
iter_content(chunk_size=...)分块读取,而非直接操作r.raw(当然也可以用r.raw.read(chunk_size),但iter_content会自动处理空块场景)。 - 别忘了加
r.raise_for_status(),避免下载失败时还继续写入无效内容。 - 用zlib时一定要设置
wbits=zlib.MAX_WBITS | 16,否则生成的是deflate格式文件,大部分解压工具无法识别。
内容的提问来源于stack exchange,提问作者delica
相关产品推荐
相关产品推荐

