質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

3277閲覧

Pythonを使用して複数ファイルを解凍したい(Lambda)

退会済みユーザー

退会済みユーザー

総合スコア0

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2022/10/25 01:55

前提

表題の通りです。
参考にしたコード(URL:https://qiita.com/kitamuratomokazu/items/2c9fe087dfdca4482788)

import boto3 import zipfile import traceback import os print('Loading function') s3 = boto3.resource('s3') s3_client = boto3.client('s3') def lambda_handler(event, context): # Get the object from the event and show its content type bucket = event['Records'][0]['s3']['bucket']['name'] key = event['Records'][0]['s3']['object']['key'] try: s3_client.download_file(bucket, key, '/tmp/file.zip') print('download') zfile = zipfile.ZipFile('/tmp/file.zip') namelist = zfile.namelist() print(namelist) for filename in namelist: if not os.path.basename('/tmp/'+filename): os.mkdir('/tmp/'+filename) else: f = open('/tmp/' + str(filename), 'wb') data = zfile.read(filename) f.write(data) f.close() for filename in namelist: s3_client.upload_file('/tmp/'+filename, bucket, key + filename) except Exception as e: print(e) print(traceback.format_exc())

実現したいこと

・AWS環境でLambda⇒S3をトリガーにS3にアップロードしたzipファイルを自動的に解凍したいです。
・前提ではJPGですが、今回の場合ですがzipフォルダーには例えば
testフォルダ
|-A.txt
|-B.xlsx
という階層になっています。
参考にしているコードだとJPGファイル単体をzipファイルを解凍できるのですが
フォルダを挟んだ場合の複数ファイルだとできません。Cloudwatch Logに以下通りのエラーが表示されました。

発生している問題・エラーメッセージ

message "Loading function "START RequestId: cfceab81-1e66-4a10-aa0e-a720c613b635 Version: $LATEST "download "['test/A.txt', 'test/B.xlsx'] "[Errno 2] No such file or directory: '/tmp/test/A.txt' "Traceback (most recent call last): "File ""/var/task/lambda_function.py"", line 33, in lambda_handler "f = open('/tmp/' + str(filename), 'wb') "FileNotFoundError: [Errno 2] No such file or directory: '/tmp/test/A.txt' "END RequestId: cfceab81-1e66-4a10-aa0e-a720c613b635 "REPORT RequestId: cfceab81-1e66-4a10-aa0e-a720c613b635 Duration: 383.95 ms Billed Duration: 384 ms Memory Size: 128 MB Max Memory Used: 73 MB Init Duration: 408.20 ms

試したこと

zip解凍後、Lambdaの「/tmp/」に格納される流れですが、「/tmp/」だとOKですが
「/tmp/test」だとディレクトリが見つかりませんと表示されるので、
zipで展開したらファイルを移動させればいいと思い、以下通りにしてみました。

#(5行目に追加) import shutil ... zfile = zipfile.ZipFile('/tmp/file.zip') namelist = zfile.namelist() print(namelist) #(追加部分)展開したファイルをtmp配下に移動する shutil.move(namelist, '/tmp/') for filename in namelist: if not os.path.basename('/tmp/'+filename): os.mkdir('/tmp/'+filename) ...

しかしログには以下通りに出力されました。

message Loading function START RequestId: e1e5472e-35a4-461e-a5af-a5c0c204d8ad Version: $LATEST download ['test/A.txt', 'test/B.xlsx'] stat: path should be string, bytes, os.PathLike or integer, not list Traceback (most recent call last): File ""/var/task/lambda_function.py"", line 27, in lambda_handler shutil.move(namelist, '/tmp/') File ""/var/lang/lib/python3.9/shutil.py"", line 812, in move if _samefile(src, dst): File ""/var/lang/lib/python3.9/shutil.py"", line 220, in _samefile return os.path.samefile(src, dst) File ""/var/lang/lib/python3.9/genericpath.py"", line 100, in samefile s1 = os.stat(f1) TypeError: stat: path should be string, bytes, os.PathLike or integer, not list END RequestId: e1e5472e-35a4-461e-a5af-a5c0c204d8ad REPORT RequestId: e1e5472e-35a4-461e-a5af-a5c0c204d8ad Duration: 404.88 ms Billed Duration: 405 ms Memory Size: 128 MB Max Memory Used: 74 MB Init Duration: 431.47 ms

pythonをよく理解できず仕舞いですみませんが、
複数ファイルを展開する際に解凍したらファイルを/tmpに移動させるのか
または他の方法がよければご指摘頂きますようお願いします。

補足情報(FW/ツールのバージョンなど)

AWS Lambda , Python 3.9

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

ファイル展開の面倒な部分はpythonが用意してくれているライブラリの機能(ZipFile.extractall)を活用するのがいいのではないでしょうか。サブディレクトリもうまく扱ってくれます。

python

1zfile = zipfile.ZipFile('/tmp/file.zip') 2namelist = zfile.namelist() 3 4zfile.extractall('/tmp') 5 6for filename in namelist: 7 if os.path.isfile('/tmp/' + filename): 8 s3_client.upload_file('/tmp/' + filename, bucket, key + filename)

投稿2022/10/25 08:11

bsdfan

総合スコア4560

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2022/10/25 08:34

ご回答頂いた内容で無事実現したいことが叶いました。 ありがとうございました。
guest

0

追記:
コードの問題と言うより、zipファイルの作り方の問題だったようです。プログラムが想定する作り方があり、それに沿ってなかった。
コメント参照。

下記のコードだと、ディレクトリかどうかの判断をしてないので、逆にディレクトリのエントリーがあると駄目ですね。
残しておきますが、使わないでください。

=== OLD ===
エラーの原因はお察しの通り、/tmp/testが存在しないことです。
コードに、os.mkdirしている部分があるので、「なければ作る」ことをやろうとしたのでしょうが、あるかないかの判定方法も、作る物も間違っています。
ファイル作成がelseにあるのもおかしい。

Python

1 dirname = os.path.dirname('/tmp/'+filename) 2 if not os.path.exists(dirname): 3 os.mkdir(dirname) 4 f = open('/tmp/' + str(filename), 'wb') 5 data = zfile.read(filename) 6 f.write(data)

投稿2022/10/25 04:15

編集2022/10/25 05:26
otn

総合スコア84505

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

bsdfan

2022/10/25 05:01 編集

zipファイルに、サブディレクトリが単体のエントリーとして入っている場合は、質問のコードでうまく動くんだと思います。(ディレクトリの判定はあまりきれいじゃないですが) ディレクトリを単体のエントリーで入れるか入れないかは、使うアーカイバーによって動作が違っていそうです。
otn

2022/10/25 05:20

なるほど。Linuxのzipコマンドでも、ディレクトリを指定すれば、ディレクトリのエントリーが出来ますね。 ディレクトリエントリーの有無は、あまり意識してなかったです。 ということで、回答としては、file.zip を作る時に、 zip file.zip test/* あるいは zip file.zip test/A.txt test/B.xlsx のように作るのでなく、 zip -r file.zip test あるいは zip file.zip test test/A.txt test/B.xlsx のようにして作れば良かったと言うことですね。 失礼しました。
退会済みユーザー

退会済みユーザー

2022/10/25 06:29

zipファイルを作成した時にどうにかすればいいということですね。 記載の通り、zipファイルの中身が単体だと解凍できますが、中身がディレクトリでディレクトリの中に複数ファイルが存在すると展開できません。 解決策についてですがあまりよく理解できず、再度の質問となりすみませんが確認させてください。 > s3_client.download_file(bucket, key, '/tmp/file.zip') この部分でS3からアップロードしたzipファイルを呼び出していますが > zfile = zipfile.ZipFile('/tmp/file.zip') ここでzipfileモジュールを使って解凍していますが ここでどのような処理をすればいいのかが理解できずじまいです。 修正箇所が違うようでしたら指摘頂ければと思います。
otn

2022/10/25 10:13

お書きのファイルであれば、回答のプログラムで解凍できます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問