web-dev-qa-db-ja.com

ローカルファイルではなくストリームを使用してS3にアップロードできますか?

CSVを作成し、S3バケットにアップロードする必要があります。私はその場でファイルを作成しているので、ファイル全体をローカルに書き込み、最後にファイルをアップロードするよりも、作成中にS3バケットに直接書き込む方が良いでしょう。

これを行う方法はありますか?私のプロジェクトはPythonであり、私はこの言語にかなり慣れていません。これまでに試したことは次のとおりです。

import csv
import csv
import io
import boto
from boto.s3.key import Key


conn = boto.connect_s3()
bucket = conn.get_bucket('dev-vs')
k = Key(bucket)
k.key = 'foo/foobar'

fieldnames = ['first_name', 'last_name']
writer = csv.DictWriter(io.StringIO(), fieldnames=fieldnames)
k.set_contents_from_stream(writer.writeheader())

私はこのエラーを受け取りました:BotoClientError:s3はチャンク転送をサポートしません

更新:S3に直接書き込む方法を見つけましたが、既に書き込んだ行を実際に削除せずにバッファをクリアする方法を見つけることができません。したがって、たとえば:

conn = boto.connect_s3()
bucket = conn.get_bucket('dev-vs')
k = Key(bucket)
k.key = 'foo/foobar'

testDict = [{
    "fieldA": "8",
    "fieldB": None,
    "fieldC": "888888888888"},
    {
    "fieldA": "9",
    "fieldB": None,
    "fieldC": "99999999999"}]

f = io.StringIO()
fieldnames = ['fieldA', 'fieldB', 'fieldC']
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
k.set_contents_from_string(f.getvalue())

for row in testDict:
    writer.writerow(row)
    k.set_contents_from_string(f.getvalue())

f.close()

ファイルに3行を書き込みますが、メモリを解放して大きなファイルを書き込むことができません。追加する場合:

f.seek(0)
f.truncate(0)

ループには、ファイルの最後の行のみが書き込まれます。ファイルから行を削除せずにリソースを解放する方法はありますか?

29
inquiring minds

私は自分の質問に対する解決策を見つけましたが、他の誰かが興味を持っている場合に備えてここに投稿します。マルチパートアップロードの一部としてこれを行うことにしました。 S3にストリーミングできません。また、ストリーミングファイルを、使用したマルチパートアップロードに変更するパッケージ Smart Open を利用できます。

import smart_open
import io
import csv

testDict = [{
    "fieldA": "8",
    "fieldB": None,
    "fieldC": "888888888888"},
    {
    "fieldA": "9",
    "fieldB": None,
    "fieldC": "99999999999"}]

fieldnames = ['fieldA', 'fieldB', 'fieldC']
f = io.StringIO()
with smart_open.smart_open('s3://dev-test/bar/foo.csv', 'wb') as fout:
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()
    fout.write(f.getvalue())

    for row in testDict:
        f.seek(0)
        f.truncate(0)
        writer.writerow(row)
        fout.write(f.getvalue())

f.close()
26
inquiring minds

docs によると、可能です

s3.Object('mybucket', 'hello.txt').put(Body=open('/tmp/hello.txt', 'rb'))

したがって、通常の方法でStringIOを使用できます

Updatesmart_open @inquiring minds answerからのlibがより良い解決策です

4
El Ruso