S3にあるテキストファイルの文字コード変換をするPythonスクリプトを考える

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

  • S3にテキストファイル(主にcsvなど)が配置されるが文字コードがUTF-8になっていない
  • gzip等に圧縮されていない

こういったファイルをAWS LambdaでさくっとUTF-8 + gzipに変換したいケースがしばしばあると感じているのですが、意外とネット上にドンピシャな記事が見つけられないので自分で書いてみようと思います。

サンプルコード

とりあえず、結論としてサンプルコードから。 以下を前提としています。

  • S3イベントから呼び出されるAWS Lambda関数
  • 環境変数のIN_CHAR_SETとOUT_CHAR_SETに文字コードを設定
import boto3
import gzip
import tempfile
import os

CHUNK_SIZE = 1024 * 1024 * 1024
IN_CHAR_SET = os.environ.get('IN_CHAR_SET')
OUT_CHAR_SET = os.environ.get('OUT_CHAR_SET')


def handler(event, context):
    s3_bucket_name = event['Records'][0]['s3']['bucket']['name']
    s3_key = event['Records'][0]['s3']['object']['key']
    file_name = os.path.basename(s3_key)
    s3_dir_key = os.path.dirname(s3_key)

    s3_client = boto3.client('s3')
    s3_object = s3_client.get_object(
        Bucket=s3_bucket_name,
        Key=s3_key,
    )
    with tempfile.TemporaryDirectory() as tmpdir:
        gzip_file_name = f'{file_name}.gz'
        tmp_file_path = os.path.join(tmpdir, gzip_file_name)
        with gzip.open(tmp_file_path, mode='at', encoding=OUT_CHAR_SET) as gz_file:
            text = ''
            for stream in s3_object['Body'].iter_lines():
                text += f'{stream.decode(IN_CHAR_SET)}\n'
                if len(text) >= CHUNK_SIZE:
                    gz_file.write(text)
                    text = ''
            gz_file.write(text)
        s3_upload_key = os.path.join(s3_dir_key, gzip_file_name)
        s3_client.upload_file(
            Bucket=s3_bucket_name,
            Key=s3_upload_key,
            Filename=os.path.join(tmpdir, gzip_file_name),
        )
        s3_client.delete_object(Bucket=s3_bucket_name, Key=s3_key)

ポイント

  • get_objectでStreamingBodyを取得
  • iter_linesで一行ずつ読み込み(大きなファイルを一度に読み込むとメモリ不足になる為)
  • 一度に読み込むテキスト量はCHUNK_SIZEで制御
  • tempfile.TemporaryDirectory()で作成した一時フォルダにgzipファイルを保存
  • 同じファイル名で末尾に.gzを付与してアップロード
  • 元ファイルは最後に削除

CHUNK_SIZEの大きさ、元のファイルを消さないでおきたい、別の場所に書き出してほしい等、要件や環境によって細かい違いはあるかと思いますが、ある程度は汎用的に使用できるものになっているのではないかと思います。

注意点としてはローカルストレージを使用している為、大きなファイルを処理する際はメモリに加えてエフェメラルストレージの拡張が必要な場合があります。

参考のひとつとなれば幸いです。

おまけ

今回のコードをChatGPT先生にレビューしてもらいました。

すごい。

アノテーション株式会社について

アノテーション株式会社は、クラスメソッド社のグループ企業として「オペレーション・エクセレンス」を担える企業を目指してチャレンジを続けています。「らしく働く、らしく生きる」のスローガンを掲げ、様々な背景をもつ多様なメンバーが自由度の高い働き方を通してお客様へサービスを提供し続けてきました。現在当社では一緒に会社を盛り上げていただけるメンバーを募集中です。少しでもご興味あれば、アノテーション株式会社WEBサイトをご覧ください。