🌊

S3にあるファイルをzipに圧縮してそのままアップロードするPythonスクリプト

2021/09/09に公開

はじめに

S3に置いてあるファイルを、まとめてzipにしたいことってありませんか?
今回は、PythonでS3のファイルを扱うのに便利なs3fsというライブラリを利用して上記のことを実施します。

コード

やっていることはシンプルなのでソースコードのみ載せます。
今回はビルトインライブラリのzipfileを利用しましたが、他のgzipとかでも同様にできるはずです。

import io
import zipfile
import s3fs

fs = s3fs.S3FileSystem(anon=False)
S3_BUCKET_NAME = "{YOUR_BUCKET_NAME}"
S3_ZIP_OUTPUT_FULL_PATH = "s3://.../.../file.zip"

# s3fsだと * で複数のファイルを一度に選択できます。
file_paths = [f"s3://{f}" for f in fs.glob(f"s3://{S3_BUCKET_NAME}/path/to/files=*")]
file_names = [f.split("/")[-1] for f in file_paths]

# zipのstreamを作成して、順次ファイルを読み込んでいく
zip_stream = io.BytesIO()
with zipfile.ZipFile(zip_stream, 'w', compression=zipfile.ZIP_DEFLATED) as new_zip:
    for file_name, file_path in zip(file_names, file_paths):
        # file_pathにはS3のフルパスが、
        # file_nameにはzipに格納する時に入るファイル名です。
        # 現在だと、zipの直下に入れるようになっているので、フォルダを分けたい場合は
        # 適宜 `/` で区切るようにしてください。
        new_zip.writestr(file_name, fs.open(file_path, "rb").read())

# 書き込み処理
zip_stream.seek(0)
with fs.open(S3_ZIP_OUTPUT_FULL_PATH, "wb") as f:
    f.write(zip_stream.read())

Pythonのdictをそのままアップロードしたい場合は次のようなコードになります。

import json

data = {"key1": "value1"}
zip_stream = io.BytesIO()
with zipfile.ZipFile(zip_stream, 'w', compression=zipfile.ZIP_DEFLATED) as new_zip:
    json_stream = io.StringIO()
    json.dump(data, json_stream)
    new_zip.writestr("role_mapping.json", bytes(json_stream.getvalue(), encoding="utf-8"))

おわりに

今回、記事を作成したきっかけがここ半年くらいで
2回ほどS3にあるファイルをzipにまとめて上げるみたいなことをしており、
ネットを探してもパッとは出てこなかったので記事にまとめました。

備忘録的な側面が強いですが誰かの役に立てば嬉しいです。

GitHubで編集を提案

Discussion