LoginSignup
47
60

More than 5 years have passed since last update.

AWS Lambda Python S3でフォルダ以下のファイル一覧を取得する

Last updated at Posted at 2018-11-18

いろいろハマったのでメモ

  • ファイル情報を1回で取れない
  • 一度に1000個まで
  • Lambdaの15分制限を超えた
  • S3にフォルダはない

あるフォルダ以下のファイル一覧をCSVで出力

Lambdaのログでは行数に制限があるのでCSVで保存します。
拡張子 mp4 のみを検索します。
ファイル名、ファイルサイズ、更新日時も出力します。

S3Bucket    = 'bucket'
S3KeyPrefix = 'folder/'

s3 = boto3.resource('s3')
bucket = s3.Bucket(S3Bucket)
objs = bucket.meta.client.list_objects_v2(Bucket=bucket.name, Prefix=S3KeyPrefix)

csv = '{},{},{}\n'.format('file', 'size_mb', 'date')
for o in objs.get('Contents'):
    key = o.get('Key')
    size = o.get('Size')
    date = o.get('LastModified')
    if key[-4:]=='.mp4':
        csv += '{},{},{}\n'.format(key, int(size/1024/1024), date.strftime("%Y-%m-%d %H:%M:%S"))

s3_resource = boto3.resource('s3') 
s3_resource.Object(S3Bucket, 'file_list.csv').put(Body=csv)  

S3のフォルダ一覧(ファイル数、サイズ、更新日時付き)

S3のフォルダ一覧を出力します。
サブフォルダは含みません。
フォルダ名、ファイル数、サイズ、一番新しい更新日時を出力します。

S3Bucket    = 'bucket'
S3KeyPrefix = 'folder/'

s3 = boto3.resource('s3')
bucket = s3.Bucket(S3Bucket)
objs = bucket.meta.client.list_objects(Bucket=bucket.name, Prefix=S3KeyPrefix, Delimiter='/')

csv = '{},{},{},{}\n'.format('folder', 'count', 'size_mb', 'date')
for o in objs.get('CommonPrefixes'):
    folder = o.get('Prefix')
    files = bucket.meta.client.list_objects_v2(Bucket=bucket.name, Prefix=folder)

    total_size = 0
    file_count = 0
    last_date = datetime(2000, 1, 1)
    for f in files.get('Contents'):
        if f.get('Key')[-1:]!="/":          
            total_size += f.get('Size')
            file_count += 1
            date = datetime.strptime(f.get('LastModified').strftime("%Y-%m-%d"), "%Y-%m-%d")
            if last_date<date:
                last_date=date

    csv += '{},{},{},{}\n'.format(folder, file_count, int(total_size/1024/1024), last_date.strftime("%Y-%m-%d"))

s3_resource = boto3.resource('s3') 
s3_resource.Object(S3Bucket, 'folder_list.csv').put(Body=csv) 

S3のフォルダ一覧(1000個以上に対応)

list_objectsは上限1000個のため、objects.all()を使用します。
2階層(/2本)までを切り取りリストに追加します。

lambda.py
from boto3 import Session

S3Bucket    = 'bucket'
S3KeyPrefix = 'folder/'

folder_list = []
sbucket = Session().resource('s3').Bucket(S3Bucket)
keys = [obj.key for obj in sbucket.objects.all()]    
for k in keys:
    ks = k.split('/')
    if len(ks)>=2:
        k2 = ks[0] +'/'+ ks[1]+'/'
        if (k2 in folder_list) == False:
            folder_list.append(k2)

S3のフォルダ一覧(1000個以上、Lambda15分制限に対応)

ファイル数が多いと上記のobjects.all()ではlambdaの最大の15分を超えました。
以下のコードでは、folder/a...検索、folder/b...検索を繰り返します。
大文字Aは不可です。a以下が1000個の場合は不可です。

preList = ['0','1','2','3','4','5','6','7','8','9','0']
preList += ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']

folder_list = []
for pre in preList:
    objs = bucket.meta.client.list_objects_v2(
        Bucket=S3Bucket,
        Prefix=S3KeyPrefix + pre,
        Delimiter='/'
    )
    if objs.get('CommonPrefixes') is None:
        continue
    for o in objs.get('CommonPrefixes'):
        folder_list.append(o.get('Prefix'))

まとめ

3年くらい実運用で使っているS3で、不要データを削除するスクリプトを作ることになりました。削除といっても保険として、Trashフォルダに移動(コピー&削除)をします。削除の前段で、ファイルやフォルダ、サイズ、日時をリスト化することから始めました。まさか一覧取得に15分もかかるとは思いませんでした。やはり本番環境は色々なことが起きます。

47
60
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
47
60