如何使用boto3从S3读取CSV文件子集(解决内存溢出问题)
解决S3大CSV文件内存溢出问题:仅读取子集
你的问题根源在于obj.get()["Body"].read()会一次性把整个CSV文件下载到内存中,后续的islice只是在内存里截取子集,根本没解决内存占用问题。下面提供两种可靠的解决方案:
方案一:流式读取+逐行截取(推荐)
直接利用S3对象的流式响应,让csv.DictReader逐行读取,配合islice只取需要的行数,全程不会加载整个文件到内存:
import boto3 import csv from itertools import islice from io import TextIOWrapper s3 = boto3.client('s3') # 获取流式响应,避免一次性下载全量 response = s3.get_object(Bucket=bucket_name, Key=file_name) # 将二进制流包装为UTF-8文本流 text_stream = TextIOWrapper(response['Body'], encoding='utf-8') # 从流中截取前10行(包含CSV表头) data = csv.DictReader(islice(text_stream, 10)) # 遍历读取到的子集数据 for row in data: print(row)
说明
response['Body']是可迭代的流对象,TextIOWrapper负责将二进制流转成文本流,csv.DictReader会逐行解析,islice会在读取到指定行数后停止,内存占用仅为当前行的大小。- 如果需要跳过表头、只取数据行,可以先手动读取表头行,再截取数据:
# 先读取表头 header = next(text_stream) # 取后续9条数据行 data = csv.DictReader(islice(text_stream, 9), fieldnames=header.strip().split(','))
方案二:使用S3范围请求(精确控制下载字节)
如果需要精确控制下载的字节数(比如只下载前100KB),可以用S3的Range参数指定字节范围,避免下载全量文件:
import boto3 import csv from io import StringIO s3 = boto3.client('s3') # 请求前10000字节(可根据实际情况调整范围) response = s3.get_object(Bucket=bucket_name, Key=file_name, Range='bytes=0-9999') content = response['Body'].read().decode('utf-8') # 处理可能的不完整行:截断到最后一个换行符,保证CSV格式合法 last_newline = content.rfind('\n') if last_newline != -1: content = content[:last_newline+1] # 解析CSV子集 data = csv.DictReader(StringIO(content)) for row in data: print(row)
说明
Range参数的格式为bytes=start-end,比如bytes=0-9999表示下载第0到第9999字节(共10000字节)。- 由于CSV行可能跨字节范围,需要手动截断到最后一个换行符,避免解析不完整的行导致报错。
内容的提问来源于stack exchange,提问作者HuLu ViCa
相关产品推荐
相关产品推荐

