我正在尝试将从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
答案 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。