突破内存限制:Requests流式上传大文件完全指南

突破内存限制:Requests流式上传大文件完全指南

【免费下载链接】requests 【免费下载链接】requests 项目地址: https://gitcode.com/gh_mirrors/req/requests

你是否遇到过上传GB级文件时程序崩溃?是否因服务器超时错误反复重试?Requests流式上传(Streaming Upload)技术能帮你解决这些问题。本文将通过3个实用场景、5段核心代码和2种高级技巧,让你彻底掌握大文件分块上传的实现方法,无需复杂框架即可轻松处理超大型文件传输。

流式上传原理与优势

传统文件上传需要将整个文件读入内存,这会导致内存占用过高和上传超时。而流式上传采用分块传输机制,将文件分割成小块逐步发送,实现"边读边传"的高效模式。

Requests Logo

核心优势对比:

上传方式内存占用最大支持文件网络容错
传统上传O(n)受内存限制低,中断需重传全部
流式上传O(1)无限制高,可断点续传

Requests通过src/requests/models.py中的PreparedRequest类实现流式传输,当检测到数据流时自动启用分块编码(Transfer-Encoding: chunked)。

基础实现:文件对象流式上传

最简洁的流式上传方式是直接传递文件对象。Requests会自动处理分块传输,无需手动分割文件:

import requests

def stream_upload_basic(url, file_path):
    with open(file_path, 'rb') as f:
        # 直接传递文件对象,Requests自动启用流式上传
        response = requests.post(
            url,
            data=f,  # 文件对象作为data参数
            headers={'Content-Type': 'application/octet-stream'}
        )
    return response.status_code

# 使用示例:上传10GB视频文件
stream_upload_basic('https://api.example.com/upload', '/data/large_video.mp4')

关键实现原理在src/requests/models.py中:当检测到data参数是可迭代对象且非字符串/列表时,自动启用流式模式,并设置Transfer-Encoding: chunked头部。

高级控制:自定义分块迭代器

对于需要精确控制分块大小或添加进度监控的场景,可以实现自定义迭代器。这种方式允许你控制每个分块的大小、添加校验和或实现上传进度显示:

import requests
from requests.utils import iter_slices  # 导入分块工具函数

def file_chunk_iterator(file_path, chunk_size=8192):
    """生成文件分块迭代器,默认8KB分块"""
    with open(file_path, 'rb') as f:
        while True:
            chunk = f.read(chunk_size)
            if not chunk:
                break
            yield chunk  # 逐个返回文件分块

def stream_upload_with_progress(url, file_path, chunk_size=8192):
    # 创建分块迭代器
    file_iterator = file_chunk_iterator(file_path, chunk_size)
    
    # 添加进度监控(可选)
    total_size = os.path.getsize(file_path)
    uploaded = 0
    
    def progress_hook(chunk):
        nonlocal uploaded
        uploaded += len(chunk)
        progress = (uploaded / total_size) * 100
        print(f"Upload progress: {progress:.2f}%", end='\r')
    
    # 发送流式请求
    response = requests.post(
        url,
        data=iter_slices(file_iterator, chunk_size),  # 使用分块工具
        headers={'Content-Type': 'application/octet-stream'},
        hooks={'data': progress_hook}  # 注册进度钩子
    )
    return response.status_code

上述代码使用了src/requests/utils.py中的iter_slices函数,该工具函数负责将迭代器按指定大小分割成块,是实现自定义分块的核心工具。

断点续传:中断恢复机制

网络不稳定时,断点续传功能能节省大量带宽和时间。实现思路是记录已上传位置,中断后从断点继续上传:

import requests

def resume_upload(url, file_path, resume_position=0, chunk_size=8192):
    with open(file_path, 'rb') as f:
        # 跳转到上次中断位置
        f.seek(resume_position)
        
        # 创建带Range头部的请求
        headers = {
            'Content-Type': 'application/octet-stream',
            'Content-Range': f'bytes {resume_position}-*/{os.path.getsize(file_path)}'
        }
        
        # 发送剩余部分
        response = requests.post(
            url,
            data=f,  # 从当前位置开始读取
            headers=headers
        )
    
    return response.status_code

断点续传需要服务端支持,客户端实现的关键是通过seek()方法定位文件读取位置,并使用Content-Range头部告知服务端续传位置。

性能优化与最佳实践

分块大小选择

分块大小直接影响传输效率,建议根据网络环境调整:

  • 局域网:64KB-1MB
  • 互联网:8KB-32KB
  • 高延迟网络:1KB-4KB

可通过src/requests/models.py查看Requests默认块大小(CONTENT_CHUNK_SIZE = 10 * 1024,即10KB)。

连接复用

使用Session对象复用TCP连接,减少握手开销:

# 创建持久会话
with requests.Session() as session:
    # 会话内所有请求复用连接
    response = session.post(url, data=file_object)

错误处理与重试

添加重试机制提高稳定性:

from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

def create_retry_session(retries=3, backoff_factor=0.5):
    session = requests.Session()
    retry_strategy = Retry(
        total=retries,
        backoff_factor=backoff_factor,
        status_forcelist=[429, 500, 502, 503, 504]
    )
    adapter = HTTPAdapter(max_retries=retry_strategy)
    session.mount("https://", adapter)
    session.mount("http://", adapter)
    return session

# 使用带重试机制的会话上传
session = create_retry_session()
response = session.post(url, data=file_object)

完整案例:大文件上传工具

整合上述技术,实现一个生产级的大文件上传工具:

import os
import requests
from requests.utils import iter_slices

class LargeFileUploader:
    def __init__(self, chunk_size=8192, retries=3):
        self.chunk_size = chunk_size
        self.session = self._create_session(retries)
        
    def _create_session(self, retries):
        """创建带重试机制的会话"""
        session = requests.Session()
        retry_strategy = requests.adapters.Retry(
            total=retries,
            backoff_factor=0.5,
            status_forcelist=[429, 500, 502, 503, 504]
        )
        adapter = requests.adapters.HTTPAdapter(max_retries=retry_strategy)
        session.mount("https://", adapter)
        session.mount("http://", adapter)
        return session
        
    def upload(self, url, file_path, progress_callback=None):
        """流式上传文件"""
        file_size = os.path.getsize(file_path)
        
        with open(file_path, 'rb') as f:
            # 创建分块迭代器
            def file_iterator():
                while True:
                    chunk = f.read(self.chunk_size)
                    if not chunk:
                        break
                    if progress_callback:
                        progress_callback(len(chunk))
                    yield chunk
            
            # 发送请求
            response = self.session.post(
                url,
                data=iter_slices(file_iterator(), self.chunk_size),
                headers={'Content-Type': 'application/octet-stream'}
            )
            
        return response.status_code

# 使用示例
if __name__ == "__main__":
    uploader = LargeFileUploader(chunk_size=16384)  # 16KB分块
    
    # 定义进度回调
    total_uploaded = 0
    def update_progress(chunk_size):
        global total_uploaded
        total_uploaded += chunk_size
        progress = (total_uploaded / os.path.getsize("large_file.iso")) * 100
        print(f"Progress: {progress:.2f}%", end='\r')
    
    # 执行上传
    uploader.upload(
        "https://api.example.com/upload",
        "large_file.iso",
        progress_callback=update_progress
    )

总结与扩展阅读

流式上传是处理大文件的高效解决方案,通过本文你已掌握:

  1. 基础流式上传:使用文件对象直接传输
  2. 高级控制:自定义分块迭代器和进度监控
  3. 断点续传:中断恢复机制实现
  4. 性能优化:分块大小调整和连接复用

官方文档:docs/user/advanced.rst中包含更多高级用法。对于需要更复杂功能的场景,可以研究src/requests/adapters.py中的适配器机制,实现自定义传输逻辑。

掌握流式上传技术,让你的应用轻松应对GB级文件传输挑战!

【免费下载链接】requests 【免费下载链接】requests 项目地址: https://gitcode.com/gh_mirrors/req/requests

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值