codeAB 2019-10-23
背景: 使用脚本从S3下载下来的CSV文件打开发现是乱码,但是在网页上面点击下载按钮下载后却能正常打开.
研究发现,在S3文件属性的元数据中有Content-Encoding值是gzip
浏览器下载的时候会识别这个值,然后在帮你自动减压后下载. 但是利用官方boto3包的download_fileobj()方法中,却无法指定对应的参数(不知道以后不会优化).
下载的话就比较简单了,下载后直接利用gzip解压后再处理数据即可.
import boto3 import gzip import csv s3 = boto3.client('s3') bucket = 'my_bucket' download_key = 'my.csv' file_path = '/tmp/my.csv' with open('/tmp/my.csv.gz', 'wb') as file_date: s3.download_fileobj(bucket, download_key, file_date) g = gzip.GzipFile(mode="rb", fileobj=open('/tmp/my.csv.gz', 'rb')) open(file_path, "wb").write(g.read()) csv_file_open = open(file_path, 'r') csv_file = csv.reader(csv_file_open)
上传的我研究了好久.因为我发现upload_file()方法中也无法提供Content-Encoding参数,虽然我找到了ExtraArgs参数中可以添加Metadata的字段,然后发现这个是个自定义元数据用的.会自动转换成x-amz-meta-content-encoding.这就很扯淡了.
s3_resource.meta.client.upload_file(file_path, bucket, key, ExtraArgs={'Metadata': {'Content-Encoding': 'gzip'}})
进一步研究发现在copy_object()方法中ContentEncoding 参数才是真正用来设置S3文件属性的元数据中的Content-Encoding值.
所以有一种方法是先用uploadfile上传数据,然后在用copy_object()拷贝后修改Content-Encoding属性.(这样比较蛋疼)
最后发现put_object()方法也带有这个参数,这样的话我们可以利用put_object方法来操作.代码片段如下.自己先压缩好gzip文件.
f = open('/tmp/my_gz.csv', 'rb') response = s3.put_object(Body=f, Bucket=bucket, Key='my.csv', ContentEncoding='gzip')