And*_*rei 5 python amazon-s3 azure-storage-blobs
我需要将一个大型 Azure Blob 复制到 AWS S3,而不在内存中保留它的副本。经过一番谷歌搜索后,我发现了一堆我在以下脚本中组合的示例。尽管如此,这仍然将数据加载到内存中。有什么好的方法可以避免吗?
import boto3
from azure.storage.blob import BlobClient
with io.BytesIO() as input_stream, io.BytesIO() as output_stream:
blob_client = BlobClient.from_connection_string(
conn_str=AZURE_CONNECTION_STRING,
container_name=container,
blob_name=filename,
)
blob_client.download_blob().readinto(input_stream)
input_stream.seek(0)
shutil.copyfileobj(input_stream, output_stream)
output_stream.seek(0)
boto3.resource("s3").Object(BUCKET_NAME, s3_key).put(Body=output_stream)
Run Code Online (Sandbox Code Playgroud)
该 blob 的副本位于内存中,因为您似乎正在一口气读取它。您正在初始化 的两个实例io.BytesIO
,但随后您正在使用 读取整个 blob blob_client.download_blob().readinto(input_stream)
。
我认为你应该尝试的是读取(并放入)blob 块,一次一大块,避免将其全部读取到内存中。
在上传方面 (s3),您可以通过两种方式解决该问题。您可以:
.upload()
来发起,然后.upload_part()
上传每个部分(chunk),或者.upload_fileobj()
负责一次提供一个块据我所知,似乎blob_client.download_blob()
已经返回了一个名为 的类文件对象StorageStreamDownloader
,它实现了一个chunks()
方法。我找不到合适的文档,但根据源代码,似乎它返回了一个您可以使用的迭代器。
因此,请考虑这样的事情(我目前无法访问任何 azure/s3 服务,因此此代码可能无法开箱即用):
import boto3
from boto3.s3.transfer import TransferConfig, S3Transfer
blob_client = BlobClient.from_connection_string(
conn_str=AZURE_CONNECTION_STRING,
container_name=container,
blob_name=filename,
)
s3 = boto3.resource('s3')
mpu = s3.create_multipart_upload(Bucket=BUCKET_NAME, Key=s3_key)
mpu_id = mpu["UploadId"]
blob = blob_client.download_blob()
for part_num, chunk in enumerate(blob.chunks()):
s3.upload_part(
Body=chunk,
Bucket=BUCKET_NAME,
Key=s3_key,
UploadId=mpu_id,
PartNumber=part_num,
)
Run Code Online (Sandbox Code Playgroud)
就像我提到的 - 我现在无法访问任何 blob 存储/s3 资源,因此我查看了代码。但总体思路应该是一样的。通过使用.chunks()
blob,您应该只将一小块数据提取到内存中,将其上传(使用 MPU)到 S3 并立即丢弃。