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))
これにより、ファイルがフォルダーに存在しないというエラーが発生します。どうやら同じフォルダに同じ名前のファイルがすでにある場合は機能しますが、新しいファイルをダウンロードするとエラーが発生します。
必要な修正とは何ですか?
callback = ProgressPercentage(LOCAL_PATH_TEMP + FILE_NAME))
はProgressPercentage
オブジェクトを作成し、その__init__
メソッドを実行して、オブジェクトをcallback
としてdownload_file
メソッドに渡します。これは、__init__
メソッドが実行されるbeforedownload_file
が始まることを意味します。
__init__
メソッドで、ダウンロード先のローカルファイルのサイズを読み取ろうとしています。ダウンロードがまだ開始されていないため、ファイルが存在しないため、例外がスローされます。すでにファイルをダウンロードしている場合は、ローカルコピーが存在し、そのサイズを読み取ることができるため、問題はありません。
もちろん、これはあなたが見ている例外の原因にすぎません。ダウンロードの進行状況の最大値として_size
プロパティを使用しています。ただし、ローカルファイルのサイズを使用しようとしています。ファイルが完全にダウンロードされるまで、ローカルファイルシステムはファイルの大きさを認識せず、ファイルが現在どれだけの領域を占めているかを認識します。つまり、ファイルをダウンロードすると、フルサイズに達するまでファイルが徐々に大きくなります。そのため、ローカルファイルのサイズをダウンロードの最大サイズと見なしても意味がありません。既にファイルをダウンロードしている場合は機能するかもしれませんが、それはあまり役に立ちません。
問題の解決策は、ローカルコピーのサイズではなく、ダウンロードするファイルのサイズを確認することです。これにより、ダウンロードしているファイルの実際のサイズを取得し、ファイルが存在することを確認します(ダウンロードしなかった場合はダウンロードできません)。これを行うには、次のようにhead_object
を使用してリモートファイルのサイズを取得します。
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)
最後の注意として、コードは Boto3のドキュメント から取得しましたが、ファイルのアップロードを目的としていたため機能しませんでした。その場合、ローカルファイルがソースであり、その存在が保証されます。
progressbar
をpip3 install progressbar
とともにインストールします
import boto3, os
import progressbar
bucket_name = "<your-s3-bucket-name>"
folder_name = "<your-directory-name-locally>"
file_name = "<your-filename-locally>"
path = folder_name + "/" + file_name
s3 = boto3.client('s3', aws_access_key_id="<your_aws_access_key_id>", aws_secret_access_key="<your_aws_secret_access_key>")
statinfo = os.stat(file_name)
up_progress = progressbar.progressbar.ProgressBar(maxval=statinfo.st_size)
up_progress.start()
def upload_progress(chunk):
up_progress.update(up_progress.currval + chunk)
s3.upload_file(file_name, bucket_name, path, Callback=upload_progress)
up_progress.finish()
オブジェクトclient.head_object(Bucket=bucket, Key=filename)
は辞書です。ファイルサイズには、['ContentLength']を使用してアクセスできます。
したがって、コード:self._size = client.head_object(Bucket=bucket, Key=filename).ContentLength
は次のようになります:self._size = float(client.head_object(Bucket=bucket, Key=filename)['ContentLength'])
その後、動作します。ありがとう!
これを行おうとすると、誰かがこの質問に出くわす可能性があります(質問のタイトルに従って)。私が知っている最も簡単な方法は、s3アップロードの進行状況を表示することです。
プログレスバーライブラリをプロジェクトにインポートします。これは私が使用したものです: https://github.com/anler/progressbar
次に:
import progressbar
from hurry.filesize import size
import boto3
bucket = "my-bucket-name"
s3_client = boto3.resource('s3')
...
...
# you get the filesize from wherever you have the file on. your system maybe?
filesize = size(file)
up_progress = progressbar.AnimatedProgressBar(end=filesize, width=50)
def upload_progress(chunk):
up_progress + chunk # Notice! No len()
up_progress.show_progress()
s3_client.meta.client.upload_file(file, bucket, s3_file_name, Callback=upload_progress)
ここで注意する重要なことは、Callbackパラメータ(大文字のC)の使用です。基本的に、s3にアップロードされたバイト数を返します。したがって、元のファイルサイズがわかっている場合は、いくつかの簡単な計算で進捗バーが表示されます。その後、任意のプログレスバーライブラリを使用できます。
@Kshitij Marwah
、@yummies
、nicolas.f.g
の投稿へのクレジット1.9.96
(pip
を介したdl)threading
class ProgressPercentage(object):
def __init__(self, o_s3bucket, key_name):
self._key_name = key_name
boto_client = o_s3bucket.meta.client
# ContentLength is an int
self._size = boto_client.head_object(Bucket=o_s3bucket.name, Key=key_name)['ContentLength']
self._seen_so_far = 0
sys.stdout.write('\n')
def __call__(self, bytes_amount):
self._seen_so_far += bytes_amount
percentage = (float(self._seen_so_far) / float(self._size)) * 100
TERM_UP_ONE_LINE = '\033[A'
TERM_CLEAR_LINE = '\033[2K'
sys.stdout.write('\r' + TERM_UP_ONE_LINE + TERM_CLEAR_LINE)
sys.stdout.write('{} {}/{} ({}%)\n'.format(self._key_name, str(self._seen_so_far), str(self._size), str(percentage)))
sys.stdout.flush()
C
の大文字のCallback
に注意してください(これはオンラインドキュメントとは異なります)
progress = ProgressPercentage(o_s3bucket, key_name)
o_s3bucket.download_file(key_name, full_local_path, Callback=progress)
ここで、o_s3bucket
は:
bucket_name = 'my_bucket_name'
aws_profile = 'default' # this is used to catch creds from .aws/credentials ini file
boto_session = boto3.session.Session(profile_name=aws_profile)
o_s3bucket = boto_session.resource('s3').Bucket(bucket_name)
hth
公式ドキュメント に続いて、進行状況の追跡を適用することはそれほど難しくありません(download_file関数とupload_file関数は類似しています)。以下は、好ましい方法でデータサイズを確認するためにいくつかの変更を加えた完全なコードです。
import logging
import boto3
from botocore.exceptions import ClientError
import os
import sys
import threading
import math
ACCESS_KEY = 'xxx'
SECRET_KEY = 'xxx'
REGION_NAME= 'ap-southeast-1'
class ProgressPercentage(object):
def __init__(self, filename, filesize):
self._filename = filename
self._size = filesize
self._seen_so_far = 0
self._lock = threading.Lock()
def __call__(self, bytes_amount):
def convertSize(size):
if (size == 0):
return '0B'
size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
i = int(math.floor(math.log(size,1024)))
p = math.pow(1024,i)
s = round(size/p,2)
return '%.2f %s' % (s,size_name[i])
# To simplify, assume this is hooked up to a single filename
with self._lock:
self._seen_so_far += bytes_amount
percentage = (self._seen_so_far / self._size) * 100
sys.stdout.write(
"\r%s %s / %s (%.2f%%) " % (
self._filename, convertSize(self._seen_so_far), convertSize(self._size),
percentage))
sys.stdout.flush()
def download_file(file_name, object_name, bucket_name):
# If S3 object_name was not specified, use file_name
if object_name is None:
object_name = file_name
# Initialize s3 client
s3_client = boto3.client(service_name="s3",
aws_access_key_id=ACCESS_KEY,
aws_secret_access_key=SECRET_KEY,
region_name=REGION_NAME)
try:
response = s3_client.download_file(
Bucket=bucket_name,
Key=object_name,
Filename=file_name,
Callback=ProgressPercentage(file_name, (s3_client.head_object(Bucket=bucket_name, Key=object_name))["ContentLength"])
)
except ClientError as e:
logging.error(e)
return False
return True
file_name = "./output.csv.gz"
bucket_name = "mybucket"
object_name = "result/output.csv.gz"
download_file(file_name, object_name, bucket_name )