pythonでファイルの文字コードをさくっと変換する

2020.02.07

データアナリティクス事業本部の森脇です。

pythonでの文字コード変換方法を調べていたところ、codecs.StreamRecoderを使うとさくっと変換できそうだったのですが サンプルがあまり見つからなかったので試してみました。

https://docs.python.org/ja/3/library/codecs.html#streamrecoder-objects

StreamRecoder はデータをあるエンコーディングから別のエンコーディングに変換します。 異なるエンコーディング環境を扱うとき、便利な場合があります。

pythonのバージョンは3.8.1です。

作ってみる

例として、Shift-JISのローカルファイルをutf-8に変換してみます。

import codecs
import io

src_file_path = "./sjis.txt"
src_codec = codecs.lookup("shift_jis") # 変換前の文字コード

dest_file_path = "./out-utf8.txt"
dest_codec = codecs.lookup("utf_8") # 変換後の文字コード


# ファイルオブジェクトを開く
with open(src_file_path, "rb") as src, open(dest_file_path, "wb") as dest:

    # 変換ストリームを作成
    stream = codecs.StreamRecoder(
        src,
        dest_codec.encode, src_codec.decode,
        src_codec.streamreader, dest_codec.streamwriter,
    )
    reader = io.BufferedReader(stream)

    # 書き込み
    while True:
        data = reader.read1()
        if not data:
            break
        dest.write(data)
        dest.flush()

StreamRecoderのencodeには「書き込み時の文字コード」を、decodeには「読み込み時の文字コード」のcodecを指定します。

また、io.BufferedReaderを使用してバッファリングして少しずつ書き込んでいます。これにより、大きなファイルを扱う場合でもメモリを消費しすぎることがなくなります。

io.BufferedReaderの第2引数でバッファサイズを指定することも可能です。(指定しない場合はデフォルト値)

その他

pythonが対応している文字コードは、公式ドキュメントで一覧化されていました。

https://docs.python.org/ja/3/library/codecs.html#standard-encodings

また、BOM付きのutf-8を扱いたい場合は、「utf_8_sig」を使うと良いようでした。

https://docs.python.org/ja/3/library/codecs.html#module-encodings.utf_8_sig

This module implements a variant of the UTF-8 codec. On encoding, a UTF-8 encoded BOM will be prepended to the UTF-8 encoded bytes. For the stateful encoder this is only done once (on the first write to the byte stream). On decoding, an optional UTF-8 encoded BOM at the start of the data will be skipped.

まとめ

codecs.StreamRecoderを使用することで簡単に文字コードの変換を行うことができました。 次回はS3オブジェクトを変換する方法を実践したいと思います。

参考サイト