使用Boto3向S3复制文件时,如何避免覆盖已存在文件?
解决S3同名文件重复上传覆盖的问题
问题根源
你的代码逻辑完全搞反了:遍历S3桶内的每一个对象时,只要当前对象的key和目标文件名fn2不一致,就执行上传操作。这意味着只要桶里有任何一个和fn2不同的文件,代码就会触发上传,直接覆盖掉已经存在的同名文件,完全达不到“仅当无同名文件时上传”的要求。
修复方案
方案1:高效检查文件是否存在(推荐)
使用boto3的head_object方法直接检查目标文件是否存在,比遍历所有对象效率高得多,尤其适合文件数量多的桶:
import boto3 import botocore import glob import os exchanges = ["bats"] for ex in exchanges: # 获取最新CSV文件 csv_file_list = glob.glob(f"H:\SQL_EXPORTS\eod\candles\{ex}\\*.csv") latest_file = max(csv_file_list, key=os.path.getctime) # 整理文件信息(无需手动拼接路径,直接用现成的latest_file) local_file_path = latest_file s3_file_key = os.path.basename(latest_file) print(f"待处理文件: {s3_file_key}") # 初始化S3客户端 s3_client = boto3.client('s3') bucket_name = f'eod-candles-{ex}' # 检查文件是否存在于S3桶 try: s3_client.head_object(Bucket=bucket_name, Key=s3_file_key) print(f"文件 {s3_file_key} 已存在,跳过上传") except botocore.exceptions.ClientError as e: if e.response['Error']['Code'] == '404': # 文件不存在,执行上传 s3_client.upload_file(local_file_path, bucket_name, s3_file_key) print(f"文件 {s3_file_key} 上传成功") else: # 处理其他异常(比如权限不足) print(f"检查文件时出错: {str(e)}")
方案2:遍历对象列表检查(适合小桶)
如果坚持用遍历桶对象的方式,必须先收集所有文件的key,再统一判断,而不是遍历每个对象时都执行上传:
import boto3 import glob import os exchanges = ["bats"] for ex in exchanges: csv_file_list = glob.glob(f"H:\SQL_EXPORTS\eod\candles\{ex}\\*.csv") latest_file = max(csv_file_list, key=os.path.getctime) local_file_path = latest_file s3_file_key = os.path.basename(latest_file) print(f"待处理文件: {s3_file_key}") s3 = boto3.resource('s3') bucket_name = f'eod-candles-{ex}' my_bucket = s3.Bucket(bucket_name) # 收集桶内所有文件的key existing_file_keys = [obj.key for obj in my_bucket.objects.all()] if s3_file_key not in existing_file_keys: s3.meta.client.upload_file(local_file_path, bucket_name, s3_file_key) print(f"文件 {s3_file_key} 上传成功") else: print(f"文件 {s3_file_key} 已存在,跳过上传")
额外优化点
- 删掉重复导入的
os模块 - 无需手动拼接文件路径,
latest_file已经是完整本地路径,直接使用即可 - 执行简单操作时,
s3_client比s3.resource更简洁
内容的提问来源于stack exchange,提问作者bob
相关产品推荐
相关产品推荐

