Можете ли вы загрузить на 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)
в цикл, тогда записывается только последняя строка файла. Есть ли способ освободить ресурсы без удаления строк из файла?
Ответы
Ответ 1
Я нашел решение своего вопроса, который я опубликую здесь, в случае, если кто-то еще заинтересован. Я решил сделать это как часть в многостраничной загрузке. Вы не можете переходить на 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()
Ответ 2
В соответствии с docs возможно
s3.Object('mybucket', 'hello.txt').put(Body=open('/tmp/hello.txt', 'rb'))
поэтому мы можем использовать StringIO
обычным способом