背景: 使用腳本從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')
