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

使用boto3 upload_fileobj上传至S3仅生成1000个CSV文件,与预期1050个不符的原因排查

问题排查:处理1050个JSON文件仅上传1000个CSV的原因分析

首先可以明确告诉你,这不是upload_fileobj的调用限制导致的——S3的upload_fileobj接口本身没有默认的批量上传数量限制,每次调用都是独立处理单个文件,不会因为调用次数触发1000个的上限。

那问题大概率出在其他环节,我帮你梳理几个最可能的原因:

1. S3列表接口的默认返回限制(最常见!)

你代码里用的s3_client.list_objects接口,AWS默认最多只会返回1000个对象。如果你的1050个JSON文件都在同一个前缀下,第一次调用list_objects只会拿到前1000个,剩下的50个根本没进入循环处理!

这是S3列表接口的设计限制,list_objects(v1版本)默认最大返回数是1000,超过这个数量需要手动分页获取。更推荐用list_objects_v2接口,配合ContinuationToken来遍历所有对象。

2. 部分文件的API请求或下载环节静默失败

虽然你说流程无报错,但可能有些请求环节出现了问题却没被捕获:比如某个API返回的JSON结构不对(比如没有response.snapshotLocation字段)、下载链接失效、网络超时等。如果没有加异常处理,程序会直接跳过这些失败的文件,最终数量就会不足。

3. 文件名重复导致覆盖

如果多个JSON对应的下载文件同名,后面上传的文件会直接覆盖前面的,最终目标路径里的文件数量就会少于实际处理的数量。

修复建议

针对最可能的列表分页问题,给你改一下代码逻辑,同时加上异常处理方便排查:

continuation_token = None
while True:
    # 处理分页逻辑,遍历所有S3对象
    if continuation_token:
        result = s3_client.list_objects_v2(
            Bucket=bucket_name, 
            Prefix=api_target_read_path, 
            ContinuationToken=continuation_token
        )
    else:
        result = s3_client.list_objects_v2(
            Bucket=bucket_name, 
            Prefix=api_target_read_path
        )
    
    for res in result.get('Contents', []):
        try:
            # 读取并解析JSON文件
            data = s3_client.get_object(Bucket=bucket_name, Key=res.get('Key'))
            contents = data['Body'].read().decode('utf-8')
            json_data = json.loads(contents)
            json_id = json_data['id']
            print(f"正在处理ID: {json_id}")

            # 调用API获取快照链接
            geturl = inv_avail_get_api_url + json_id
            api_response = requests.get(geturl, headers=headers)
            api_response.raise_for_status()  # 触发HTTP错误异常
            durl = api_response.json()["response"]["snapshotLocation"]

            # 下载目标文件
            download_response = requests.get(durl)
            download_response.raise_for_status()  # 触发下载错误异常

            # 处理文件名,可选:加上ID避免重复
            segments = durl.rpartition('/')
            file_name = str(segments[2]).split('?')[0]
            # file_name = f"{json_id}_{file_name}"  # 开启这行避免同名覆盖

            # 上传到目标S3路径
            s3_client.upload_fileobj(
                BytesIO(download_response.content), 
                bucket_name, 
                api_download_file_path + file_name
            )
            print(f"成功上传: {file_name}")
        
        except Exception as e:
            print(f"处理ID {json_id}失败: {str(e)}")
            # 可以在这里把失败的ID记录到文件,方便后续重试

    # 检查是否还有未遍历的对象
    if not result.get('IsTruncated'):
        break
    continuation_token = result.get('NextContinuationToken')

总结

优先排查S3列表的分页问题,这几乎是遇到“处理数量卡在1000”的最常见原因。同时通过添加异常处理和日志,能快速定位其他可能的失败环节。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 22:22:29