Python 3 で日本語ファイル名が入った zip ファイルを扱う

  • 23
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

zip ファイルは最近の仕様では UTF-8 でファイル名を格納できるのですが、多くの場合レガシーな環境依存文字コードでファイル名が格納された形式が使われています。日本語の場合は Windows に合わせて Shift-JIS (cp932) が使われることが多いです。

Python 2 では zipfile モジュールが返すファイル名はバイト文字列だったのでそのまま cp932 のファイル名が返ってきたのですが、 Python 3 では文字列が Unicode に統一されたため、 zip ファイルを読み込むとファイル名がデコードされて文字列になって返ってきます。
が、もちろん日本語の慣習がデフォルトの挙動になってるわけではないので、このままでは文字化けしてしまいます。

Python 3.4 の zipfile モジュールを読むと次のようになっていました。

            if flags & 0x800:
                # UTF-8 file names extension
                filename = filename.decode('utf-8')
            else:
                # Historical ZIP filename encoding
                filename = filename.decode('cp437')

cp932 でエンコードされた文字列をデコードして、 UnicodeDecodeError が起きないでしょうか。

>>> len(bytes(range(256)).decode('cp437'))
256

cp437 は全てのバイトを1文字に1対1でデコードするようです。
ということで、一旦 cp437 でエンコードしなおしてから改めて cp932 でデコードすれば良さそうです。

import zipfile
zf = zipfile.ZipFile('foo.zip')
for name in zf.namelist():
    print(name.encode('cp437').decode('cp932')