如何移除S3存储文件的头尾行后将文件复制到另一存储位置
实现方案
核心逻辑采用流式逐行处理,不需要将整个文件加载到内存,适合大文件处理,全程用boto3完成S3的读写操作,步骤如下:
- 从S3读取文件时使用流式响应,避免一次性加载全量数据
- 跳过第一行(头行),同时记录上一行内容,当前行写入时只写前一轮的上一行,这样遍历完所有行后,最后一行(尾行)自然不会被写入
- 采用S3分块上传写入目标路径,避免大文件单次上传失败问题
import boto3 def process_s3_file(source_bucket, source_key, target_bucket, target_key, chunk_size=8*1024*1024): s3 = boto3.client('s3') # 流式读取源文件 resp = s3.get_object(Bucket=source_bucket, Key=source_key) line_stream = resp['Body'].iter_lines() # 初始化分块上传 upload = s3.create_multipart_upload(Bucket=target_bucket, Key=target_key) upload_id = upload['UploadId'] parts = [] part_number = 1 buffer = b'' try: # 跳过头行,若头行有N行可循环执行N次next next(line_stream) # 初始化上一行变量,用来预留尾行不写入 prev_line = next(line_stream) for current_line in line_stream: # 写入上一行到缓冲区,加换行符 buffer += prev_line + b'\n' # 缓冲区达到分块大小就上传 if len(buffer) >= chunk_size: part = s3.upload_part( Bucket=target_bucket, Key=target_key, PartNumber=part_number, UploadId=upload_id, Body=buffer ) parts.append({'PartNumber': part_number, 'ETag': part['ETag']}) part_number += 1 buffer = b'' # 更新上一行为当前行 prev_line = current_line # 上传剩余的缓冲区内容 if buffer: part = s3.upload_part( Bucket=target_bucket, Key=target_key, PartNumber=part_number, UploadId=upload_id, Body=buffer ) parts.append({'PartNumber': part_number, 'ETag': part['ETag']}) # 完成分块上传 s3.complete_multipart_upload( Bucket=target_bucket, Key=target_key, UploadId=upload_id, MultipartUpload={'Parts': parts} ) except Exception as e: # 出错终止分块上传,避免残留存储碎片 s3.abort_multipart_upload( Bucket=target_bucket, Key=target_key, UploadId=upload_id ) raise e # 调用示例 if __name__ == "__main__": process_s3_file( source_bucket="替换为你的源桶名", source_key="源文件路径/abc.txt", target_bucket="替换为你的目标桶名", target_key="目标文件路径/processed_abc.txt" )
注意事项
- 该方案全程内存占用仅和你设置的
chunk_size有关,默认8MB完全不会出现内存溢出问题,适合GB级甚至TB级文本文件处理 - 如果你的头行/尾行不止1行,只需要调整跳过的行数,以及最后需要保留的行数逻辑即可
- 运行前需要确保你的账号有对应S3桶的读写权限,boto3已经完成凭证配置(可通过环境变量、
~/.aws/credentials、EC2 IAM角色等方式配置) - 如果文件行分隔符不是
\n,可以调整iter_lines()的参数或者自行处理行拆分逻辑
内容的提问来源于stack exchange,提问作者Vishal Mishra
相关产品推荐
相关产品推荐

