CSV文件从缓冲区上传到S3

时间:2017-08-15 19:13:46

标签: django python-3.x amazon-s3 boto3

我正在尝试将从Django中的模型中取出的内容上传为csv文件。我不想在本地保存文件,但将其保存在缓冲区中并上传到s3。目前,此代码不会出错,并正确上传文件,但文件为空。

file_name='some_file.csv'
fields = [list_of_fields]
header = [header_fields]

buff =  io.StringIO()
writer = csv.writer(buff, dialect='excel', delimiter=',')
writer.writerow(header)
for value in some_queryset:
    row = []
    for field in fields:
        # filling in the row
    writer.writerow(row)

# Upload to s3
client = boto3.client('s3')
bucket = 'some_bucket_name'
date_time = datetime.datetime.now()
date = date_time.date()
time = date_time.time()
dt = '{year}_{month}_{day}__{hour}_{minute}_{second}'.format(
    day=date.day,
    hour=time.hour,
    minute=time.minute,
    month=date.month,
    second=time.second,
    year=date.year,
)
key = 'some_name_{0}.csv'.format(dt)

client.upload_fileobj(buff, bucket, key)

如果我接受缓冲区的内容,那肯定是在写它:

content = buff.getvalue()
content.encode('utf-8')
print("content: {0}".format(content)) # prints the csv content

编辑:我在一个zip文件中做了类似的事情,在缓冲区中创建:

with zipfile.ZipFile(buff, 'w') as archive:

写入存档(添加我正在生成的pdf文件),一旦完成,我执行:buff.seek(0)这似乎是必要的。如果我在上面做了类似的事情,那就会出错:Unicode-objects must be encoded before hashing

4 个答案:

答案 0 :(得分:7)

好的,无视我之前的回答,我发现了实际问题。

根据upload_fileobj函数的boto3文档,第一个参数(Fileobj)需要实现一个返回字节的read()方法:

  

Fileobj(类文件对象) - 要上载的类文件对象。它至少必须实现read方法,并且必须返回字节。

read()对象上的_io.StringIO函数返回一个字符串,而不是字节。我建议将StringIO对象换成BytesIO对象,添加必要的编码和解码。

这是一个最小的工作示例。它不是最有效的解决方案 - 基本思想是将内容复制到第二个BytesIO对象。

import io
import boto3
import csv

buff = io.StringIO()

writer = csv.writer(buff, dialect='excel', delimiter=',')
writer.writerow(["a", "b", "c"])

buff2 = io.BytesIO(buff.getvalue().encode())

bucket = 'changeme'
key = 'blah.csv'

client = boto3.client('s3')
client.upload_fileobj(buff2, bucket, key)

答案 1 :(得分:1)

您是否尝试过先调用buff.flush()?你完全合理的调试检查(调用getvalue())可能会产生buff被写入的错觉,但如果你不打电话就不会这样做。

答案 2 :(得分:1)

here所述,使用put_object方法而不是upload_fileobj只需使用io.STRINGIO对象缓冲区即可完成工作。

因此,在这里,与初始示例匹配:

client = boto3.client('s3')
client.upload_fileobj(buff2, bucket, key)

将成为

client = boto3.client('s3')
client.put_object(Body=buff2, Bucket=bucket, Key=key, ContentType='application/vnd.ms-excel')

答案 3 :(得分:0)

您可以使用goofys之类的内容将输出重定向到S3。