2013-04-02 20 views
7

Geniş bir yerel dosyam var. Bu dosyanın gzipli bir sürümünü boto kütüphanesini kullanarak S3'e yüklemek istiyorum. Dosya, yüklemeden önce disk üzerinde verimli bir şekilde sıkıştırmak için çok büyüktür, bu nedenle yükleme sırasında akış halinde bir şekilde gzip olmalıdır.Boto kullanarak yükleme yaparken gzip nasıl yapılır

boto kitaplığı, okunacak dosya benzeri bir nesne olmasını bekler. set_contents_from_file().

gzip kitaplığı, fileobj; Sıkıştığında bu nesneye yazacaktır.

Bu iki işlevi birleştirmek istiyorum, ancak bir API kendi başına okumak istiyor, diğer API kendi başına yazmak istiyor; ne pasif bir operasyonu biliyor (ne yazılıyor hem de okunıyor gibi).

Bunların çalışma şekliyle nasıl birleştirileceği hakkında bir fikri olan var mı?

DÜZENLEME: Bir yanıtı (aşağıya bakın) kabul ediyorum çünkü nereye gideceğimi bildiriyor, ancak aynı soruna sahipseniz, kendi yanıtımı (ayrıca aşağıda) daha yararlı buluyor olabilirsiniz, çünkü Çok parçalı yüklemeler.

cevap

3

Gerçekten de bunun bir yolu yoktur çünkü S3 gerçek akış girişini desteklemez (yani yığın aktarım kodlaması). Yüklemeden önce İçerik Uzunluğunu ve ilk olarak gzip işleminin gerçekleştirildiğini bilmenin tek yolunu bilmelisiniz.

+0

S3 yükleme gerçekten değer boyutunu bilmek gerekecek mi? Bu gerçekten depolama sırasında hiçbir akış sıkıştırmanın gerçekleştirilemeyeceği anlamına gelir. Bunu kontrol edeceğim. – Alfe

+0

boto-s3-bucket-tuşlarında 'set_contents_from_stream()' vardır. Bu akıştaki en az ipucu mümkün olmalı, sence de öyle değil mi? – Alfe

+0

Kendi belgelerinden: 'Akış nesnesi aranabilir değil ve toplam boyut bilinmemektedir. Bu, üstbilgideki İçerik Boyutu ve Content-MD5'i belirleyemeyeceğimiz bir içeriğe sahiptir. Bu nedenle, büyük yüklemeleri için, MD5 hesaplamasındaki gecikmeden sakınılır, ancak yüklenen verilerinin bütünlüğünü doğrulayamama nedeniyle cezalandırılır. – Alfe

18

Ben garnaat tarafından kabul cevabın yorumlarında ima çözümünü uygulamaya:

import cStringIO 
import gzip 

def sendFileGz(bucket, key, fileName, suffix='.gz'): 
    key += suffix 
    mpu = bucket.initiate_multipart_upload(key) 
    stream = cStringIO.StringIO() 
    compressor = gzip.GzipFile(fileobj=stream, mode='w') 

    def uploadPart(partCount=[0]): 
     partCount[0] += 1 
     stream.seek(0) 
     mpu.upload_part_from_file(stream, partCount[0]) 
     stream.seek(0) 
     stream.truncate() 

    with file(fileName) as inputFile: 
     while True: # until EOF 
      chunk = inputFile.read(8192) 
      if not chunk: # EOF? 
       compressor.close() 
       uploadPart() 
       mpu.complete_upload() 
       break 
      compressor.write(chunk) 
      if stream.tell() > 10<<20: # min size for multipart upload is 5242880 
       uploadPart() 

O sorunsuz çalışıyor gibi görünüyor. Ve sonuçta, akış çoğu durumda verilerin sadece bir bölümüdür. Bu durumda, parçalar yaklaşık 10MB büyüktür, ama kimin umurunda? Birkaç GB parçasından bahsetmediğimiz sürece, bu konuda iyiyim. Python 3


Güncelleme:

from io import BytesIO 
import gzip 

def sendFileGz(bucket, key, fileName, suffix='.gz'): 
    key += suffix 
    mpu = bucket.initiate_multipart_upload(key) 
    stream = BytesIO() 
    compressor = gzip.GzipFile(fileobj=stream, mode='w') 

    def uploadPart(partCount=[0]): 
     partCount[0] += 1 
     stream.seek(0) 
     mpu.upload_part_from_file(stream, partCount[0]) 
     stream.seek(0) 
     stream.truncate() 

    with open(fileName, "rb") as inputFile: 
     while True: # until EOF 
      chunk = inputFile.read(8192) 
      if not chunk: # EOF? 
       compressor.close() 
       uploadPart() 
       mpu.complete_upload() 
       break 
      compressor.write(chunk) 
      if stream.tell() > 10<<20: # min size for multipart upload is 5242880 
       uploadPart() 
İlgili konular