S3からCloudfilesにファイルをコピーしていますが、ファイルをディスクに書き込まないようにしたいと思います。 Python-Cloudfilesライブラリには、必要なように見えるobject.stream()呼び出しがありますが、botoで同等の呼び出しを見つけることができません。私は次のようなことができることを願っています:
shutil.copyfileobj(s3Object.stream(),rsObject.stream())
これはbotoで可能ですか(または他のs3ライブラリだと思います)?
S3のオブジェクトを表すbotoのKeyオブジェクトは、イテレーターのように使用できるため、次のようなことができるはずです。
>>> import boto
>>> c = boto.connect_s3()
>>> bucket = c.lookup('garnaat_pub')
>>> key = bucket.lookup('Scan1.jpg')
>>> for bytes in key:
... write bytes to output stream
または、例の場合のように、次のようにすることができます。
>>> shutil.copyfileobj(key, rsObject.stream())
このスレッドの他の回答はbotoに関連していますが、S3.Objectはboto3ではもう反復できません。したがって、以下は機能しません。_TypeError: 's3.Object' object is not iterable
_エラーメッセージが生成されます。
_ s3 = boto3.session.Session(profile_name=my_profile).resource('s3')
s3_obj = s3.Object(bucket_name=my_bucket, key=my_key)
with io.FileIO('sample.txt', 'w') as file:
for i in s3_obj:
file.write(i)
_
Boto3では、オブジェクトのコンテンツはS3.Object.get()['Body']
で利用できますが、これも反復可能ではないため、以下はまだ機能しません。
_ body = s3_obj.get()['Body']
with io.FileIO('sample.txt', 'w') as file:
for i in body:
file.write(i)
_
したがって、代わりにreadメソッドを使用することもできますが、これによりWHOLE S3オブジェクトがメモリに読み込まれ、大きなファイルを処理する場合に常に可能とは限りません。
_ body = s3_obj.get()['Body']
with io.FileIO('sample.txt', 'w') as file:
for i in body.read():
file.write(i)
_
ただし、read
メソッドを使用すると、基になるストリームから読み取るバイト数を指定するamt
パラメーターを渡すことができます。このメソッドは、ストリーム全体が読み込まれるまで繰り返し呼び出すことができます。
_ body = s3_obj.get()['Body']
with io.FileIO('sample.txt', 'w') as file:
while file.write(body.read(amt=512)):
pass
_
_botocore.response.StreamingBody
_コードを掘り下げると、基になるストリームも利用可能であることがわかるため、次のように反復できます。
_ body = s3_obj.get()['Body']
with io.FileIO('sample.txt', 'w') as file:
for b in body._raw_stream:
file.write(b)
_
グーグルしながら、使用できるリンクもいくつか見ましたが、試したことはありません。
私はこの質問を見ている人の少なくとも一部が私のようになり、botoから行ごと(またはコンマごと、またはその他の区切り文字)にファイルをストリーミングする方法が欲しいと考えています。これを行う簡単な方法を次に示します。
def getS3ResultsAsIterator(self, aws_access_info, key, prefix):
s3_conn = S3Connection(**aws_access)
bucket_obj = s3_conn.get_bucket(key)
# go through the list of files in the key
for f in bucket_obj.list(prefix=prefix):
unfinished_line = ''
for byte in f:
byte = unfinished_line + byte
#split on whatever, or use a regex with re.split()
lines = byte.split('\n')
unfinished_line = lines.pop()
for line in lines:
yield line
上記の@garnaatの答えは依然として素晴らしく、100%真実です。うまくいけば、私はまだ誰かを助けます。
BotocoreのStreamingBody
にはiter_lines()
メソッドがあります:
そう:
import boto3
s3r = boto3.resource('s3')
iterator = s3r.Object(bucket, key).get()['Body'].iter_lines()
for line in iterator:
print(line)
これはストリーミング本文をラップする私の解決策です:
import io
class S3ObjectInterator(io.RawIOBase):
def __init__(self, bucket, key):
"""Initialize with S3 bucket and key names"""
self.s3c = boto3.client('s3')
self.obj_stream = self.s3c.get_object(Bucket=bucket, Key=key)['Body']
def read(self, n=-1):
"""Read from the stream"""
return self.obj_stream.read() if n == -1 else self.obj_stream.read(n)
使用例:
obj_stream = S3ObjectInterator(bucket, key)
for line in obj_stream:
print line