You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python requests库如何POST流式上传大文件 降低内存占用

Python requests大文件低内存流式上传方案

问题根因

  • 常规files参数上传:requests会默认将整个文件加载到内存构造multipart/form-data格式请求体,2GB文件会直接占用等量内存,造成内存暴涨。
  • 直接传data=open(path,'rb'):虽然文件是逐块读取不会占满内存,但请求默认使用application/octet-stream作为Content-Type,不符合绝大多数文件上传接口要求的multipart表单格式,服务端无法解析到对应文件字段,因此返回400错误。

可行实现方案

方案1:使用requests-toolbelt实现(推荐,代码最简)

这个工具库是requests官方生态维护的组件,专门提供流式multipart编码能力,不会全量加载文件到内存。
首先安装依赖:

pip install requests-toolbelt

上传代码示例:

import requests
import os
from requests_toolbelt.multipart.encoder import MultipartEncoder

# 构造流式multipart编码器,按固定块读取文件,内存仅缓存当前处理块
encoder = MultipartEncoder(
    fields={
        # 键名'file'替换为你的接口实际要求的表单字段名,和原files参数的key保持一致
        "file": (os.path.basename(path), open(path, "rb"), "application/octet-stream"),
        # 若接口需要额外传参(比如鉴权token、业务参数),直接在fields里追加键值对即可
        # "upload_token": "your_auth_token"
    }
)

response = requests.post(
    url=url,
    data=encoder,
    headers={"Content-Type": encoder.content_type},
    # 建议设置超时:连接超时10秒,读取超时设为30分钟可根据带宽调整
    timeout=(10, 1800)
)

这个方案全程内存占用稳定在几十MB以内,和上传文件大小无关,2GB甚至更大的文件都不会造成内存压力。

方案2:原生requests无第三方依赖实现

如果不想额外安装依赖,可以自己实现multipart格式的流式生成器,逐块拼接请求体:

import requests
import uuid
import os

def multipart_file_stream(file_path, field_name="file", chunk_size=10*1024*1024):
    """
    生成multipart/form-data格式的文件流,默认按10MB分块读取
    :param field_name: 接口要求的文件表单字段名
    :param chunk_size: 单次读取文件的块大小
    """
    # 生成随机boundary避免和文件内容冲突
    boundary = f"----WebKitFormBoundary{uuid.uuid4().hex}"
    file_name = os.path.basename(file_path)
    
    # 写入表单头
    yield (
        f"--{boundary}\r\n"
        f"Content-Disposition: form-data; name=\"{field_name}\"; filename=\"{file_name}\"\r\n"
        f"Content-Type: application/octet-stream\r\n\r\n"
    ).encode("utf-8")
    
    # 逐块读取文件内容
    with open(file_path, "rb") as f:
        while True:
            chunk = f.read(chunk_size)
            if not chunk:
                break
            yield chunk
    
    # 写入表单尾
    yield f"\r\n--{boundary}--\r\n".encode("utf-8")

# 生成上传流
upload_stream = multipart_file_stream(path)
# 从生成器上下文取boundary构造请求头
boundary = upload_stream.gi_frame.f_locals["boundary"]
headers = {"Content-Type": f"multipart/form-data; boundary={boundary}"}

response = requests.post(
    url=url,
    data=upload_stream,
    headers=headers,
    timeout=(10, 1800)
)

注意事项

  • 不要在请求中传入files参数,只要传入该参数,requests就会强制将所有内容加载到内存完成编码,流式处理会失效。
  • 如果你对接的接口本身支持直接接收二进制流(不需要multipart格式),那data=open(path,'rb')的写法本身是可用的,返回400时先和服务端确认要求的Content-Type和参数格式即可。
  • 大文件上传建议显式设置timeout参数,避免网络异常时请求永久挂死。

内容的提问来源于stack exchange,提问作者Baytars

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 22:57:20