2017-01-24 5 views
1

S3からboto3を使用してテキストファイルをダウンロードしようとしています。boto3とコールバックを使用してS3ファイルの進行状況を追跡します

これは私が書いたものです。

class ProgressPercentage(object): 
    def __init__(self, filename): 
     self._filename = filename 
     self._size = float(os.path.getsize(filename)) 
     self._seen_so_far = 0 
     self._lock = threading.Lock() 

    def __call__(self, bytes_amount): 
     # To simplify we'll assume this is hooked up 
     # to a single filename. 
     with self._lock: 
      self._seen_so_far += bytes_amount 
      percentage = round((self._seen_so_far/self._size) * 100,2) 
      LoggingFile('{} is the file name. {} out of {} done. The percentage completed is {} %'.format(str(self._filename), str(self._seen_so_far), str(self._size),str(percentage))) 
      sys.stdout.flush() 

と私はこれが私のファイルがフォルダ内に存在しないというエラーを与えている

transfer.download_file(BUCKET_NAME,FILE_NAME,'{}{}'.format(LOCAL_PATH_TEMP , FILE_NAME),callback = ProgressPercentage(LOCAL_PATH_TEMP + FILE_NAME)) 

を使用して、それを呼び出しています。どうやら、私はすでに同じ名前のファイルを同じフォルダに持っていると動作しますが、新しいファイルをダウンロードしているときにはエラーになります。

修正する必要はありますか?

答えて

2

callback = ProgressPercentage(LOCAL_PATH_TEMP + FILE_NAME))ProgressPercentageオブジェクトを作成し、その__init__方法を実行し、download_file方法にcallbackとしてオブジェクトを渡します。これは、__init__メソッドがの前に実行され、download_fileが開始されることを意味します。

__init__メソッドでは、ダウンロードするローカルファイルのサイズを読み取ろうとしていますが、ダウンロードがまだ開始されていないためファイルが存在しないため例外がスローされます。すでにファイルをダウンロードしている場合、ローカルコピーが存在し、そのサイズを読み取ることができるので問題はありません。

もちろん、これはあなたが見ている例外の原因です。ダウンロードの進行状況の最大値として_sizeプロパティを使用しています。ただし、ローカルファイルのサイズを使用しようとしています。ファイルが完全にダウンロードされるまで、ローカルファイルシステムはファイルの大きさを知りません。現在のところ、どれくらいのスペースが必要か分かります。つまり、ファイルをダウンロードすると、ファイルはフルサイズになるまで徐々に大きくなります。したがって、ローカルファイルのサイズをダウンロードの最大サイズと考えることは実際には意味がありません。既にファイルをダウンロードした場合にはうまくいくかもしれませんが、あまり役に立ちません。

問題を解決するには、ローカルコピーのサイズではなく、ダウンロードしようとしているファイルのサイズを確認することです。これにより、ダウンロードしているファイルの実際のサイズと、ファイルが存在するかどうかを確認できます(そうでない場合はダウンロードできないため)。あなたがBoto3 documentationからコードを得たが、それはファイルのアップロードのために意図されていたので、それは動作しませんでした、最後の注意として

class ProgressPercentage(object): 
    def __init__(self, client, bucket, filename): 
     # ... everything else the same 
     self._size = client.head_object(Bucket=bucket, Key=filename).ContentLength 

    # ... 

# If you still have the client object you could pass that directly 
# instead of transfer._manager._client 
progress = ProgressPercentage(transfer._manager._client, BUCKET_NAME, FILE_NAME) 
transfer.download_file(..., callback=progress) 

を次のようにhead_objectとリモートファイルのサイズを取得することによってこれを行うことができます。その場合、ローカルファイルはソースであり、その存在は保証されています。

2

オブジェクトclient.head_object(Bucket=bucket, Key=filename)はdictです。ファイルサイズは['ContentLength']を使ってアクセスできます。

したがってコード:
self._size = client.head_object(Bucket=bucket, Key=filename).ContentLength
はなるはずです:
self._size = float(client.head_object(Bucket=bucket, Key=filename)['ContentLength'])

そして、それが動作します。ありがとう!

関連する問題