筆者はMacを使っているのだが、Windowsを使っている取引先から、ZIP圧縮してメール送信したファイルが文字化けしているので再送して欲しいと言われることがたまにある。そこで、送信前に問題が起きないように、PythonでZIPファイルを修正するツールを作ってみよう。
macOSで作ったZIPがWindowsで文字化けする理由
最初に、macOSで作ったZIPファイルがWindowsでどのように文字化けしてしまうのか、条件を確認しておこう。次のような手順で作業すると必ず文字化けする。
1. macOSで日本語を含むファイルを用意する
2. macOSのFinderからOS標準の方法でZIPファイルを作成する
3. Windows標準の方法(エクスプローラー)で、上記2のZIPファイルを開く
なお、双方がOSの標準機能を使っている場合に文字化けする。そもそも、macOSの標準機能では、ZIP圧縮するとき、日本語ファイル名をUTF-8で圧縮するのだが、Windowsの標準機能では、ファイル名をShift_JIS(CP932)と見なして解凍してしまうという問題があるのだ。
ポイントは標準機能を使っている場合で、Windows側に「+Lhaca」や「7-Zip」などの圧縮解凍ツールをインストールしてもらえれば、この問題は起きない。それで、頻繁にやり取りをする取引先であれば、解凍ツールをインストールしてもらうだけで、問題は解決する。
しかし、取引先と年に数回しかやり取りしないとか、そもそも、お客さんなので、こちらから依頼できないという場合もある。
意図しないフォルダやファイルも追加されてしまう件
加えて、改めて文字化けしたアーカイブをよく見てみると「_ _MACOSX」というフォルダや「.DS_Store」というファイルなど、見覚えのないフォルダやファイルが作成されていることに気付くだろう。こうした意図しないファイルがあるなら、PCに詳しくないユーザーを混乱させてしまうだろう。
ZIPファイルを検査して圧縮しなおすツールを作ろう
それでは、文字エンコーディングの修正を行いつつ、macOSのメタファイルをZIPファイルから除外するプログラムを作ってみよう。下記のプログラムは、こちらにもアップロードした。
"""ZIPファイルの中身を検査するスクリプト"""
import sys
import zipfile
def main(path_input_zip):
"""メイン処理"""
# 出力ファイル名を決定 --- (※1)
path_output_zip = path_input_zip + ".fixed.zip"
with zipfile.ZipFile(path_input_zip, 'r') as zin:
with zipfile.ZipFile(path_output_zip, 'w', zipfile.ZIP_DEFLATED) as zout:
# ZIPファイルを一つずつ処理 --- (※2)
for item in zin.infolist():
# ZIPファイル内のファイル名を復元 --- (※3)
fname = decode_zip_filename(item.filename)
# macOSのメタデータを無視 --- (※4)
if fname.startswith("__MACOSX/") or fname.endswith(".DS_Store"):
print("❌無視: " + fname)
continue
# ファイルを読み込んでそのまま書き出す --- (※5)
data = zin.read(item.filename)
print("🎁追加: " + fname)
zout.writestr(fname, data) # ファイル名を指定して圧縮
print(f"検査して出力しました: {path_output_zip}")
def decode_zip_filename(name: str) -> str:
"""いろいろなエンコーディングを試してファイル名を復元する""" # --- (※6)
try:
# デフォルトでPythonはcp437として解釈
raw = name.encode("cp437")
except UnicodeEncodeError:
return name
# まずよくある文字コードを試し、最後はcp437をそのまま採用
for encoding in ("utf-8", "cp932"):
try:
return raw.decode(encoding)
except UnicodeDecodeError:
continue
return raw.decode("cp437")
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python check.py <zipfile>")
sys.exit(1)
main(sys.argv[1])
sys.exit(0)
上記のプログラムを「fix_zip.py」という名前で保存しよう。
そして、プログラムを実行するには、修正したいZIPファイルをコマンドライン引数に「python fix_zip.py (ZIPファイル)」のように指定する。
例えば、「test.zip」というZIPファイルを対象にする場合、下記のようなコマンドを実行する。すると「test.zip.fixed.zip」というファイルを生成する。
python fix_zip.py test.zip
以下はコマンドを実行したところだが、macOSのメタファイルを除外しつつ、ファイル名のエンコーディングを修正してZIPファイルを作成する様子を確認できる。
それから、作成された「test.zip.fixed.zip」というファイルをWindowsで確認すると、次のように、日本語が文字化けせず、正しいファイル名になっているのを確認できる。
実行結果が確認できたら、プログラムを確認してみよう。
(*1)では、出力ファイル名を決定している。入力されたZIPファイル名の後ろに「.fixed.zip」を付けて、新しいZIPファイル名を作る。このようにすることにより、誤って元のZIPファイルを壊さずに、安全に修正版を作ることができる。
(*2)では、ZIPファイルの中に入っているファイルを一つずつ取り出して処理する。infolist()メソッドを実行することにより、ZIPの中に入っているファイルやフォルダの情報一覧を取得できる。そのため、for文によって、すべてのフォルダ・ファイルを順番にチェックできる。
(*3)では、ファイル名を確認して、正しく読める文字列に復元する。(*4)では、macOS特有の不要ファイルを除外して、(*5)では、実際のファイルデータを読み込み、新しいZIPに書き出しています。
そして、(*6)の関数decode_zip_filenameが、ファイル名の復元処理を関数にまとめたもので、このプログラムで一番大切なポイントとなる部分だ。
今回のプログラムを作る際には、Pythonのzipfileモジュールの挙動を明確にする必要があるだろう。
Pythonのzipfileモジュールでは、ZIP内のファイル名を読み込むとき、UTF-8のフラグを確認するが、それ以外のファイルをエンコーディング「cp437」として読むようになっている。
「cp437」というのは、IBM PCの初期の標準文字セットであり、全てのバイトを1文字1バイトで扱うものだ。そのため、 一度cp437でバイト列に戻し、そのバイト列を改めてUTF-8やShift_JIS(cp932)にデコードすることで、正しいファイル名として読むことができる。
macOSでドラッグ&ドロップに対応しよう
ここまでの部分で十分目的は果たしているのだが、毎回コマンドラインから使うのは不便だ。Finderから手軽に使えるようにしたい。そこで、macOSに標準でインストールされている「Automator」アプリを利用して、実行ファイルに変換しよう。そうすることで、ドラッグ&ドロップで実行できるようになる。
「Automator」アプリを起動して「アプリケーション」を選択しよう。そして、画面左から「シェルスクリプトを実行」をドラッグして、コマンドに以下のような内容を指定しよう。
(pythonのインストールパス) (fix_zip.pyのパス) "$@"
以下は、Automatorで作成した実際の実行ファイルのアクションだ。Pythonのインストールパスと、プログラムのパスをフルパスで指定しよう。
まとめ
以上、今回は、macOSのZIPファイルが、Windowsで文字化けする問題を解決するために、ツールを作ってみた。もちろん、文字化け問題だけを解決するなら、MacWinZipperなどのツールを使えば良いのだが、不要なメタファイルを除外するなど、付加機能が追加できるのが自作ツールの良い所だ。本プログラムを参考に改良してみると良いだろう。
自由型プログラマー。くじらはんどにて、プログラミングの楽しさを伝える活動をしている。代表作に、日本語プログラミング言語「なでしこ」 、テキスト音楽「サクラ」など。2001年オンラインソフト大賞入賞、2004年度未踏ユース スーパークリエータ認定、2010年 OSS貢献者章受賞。これまで50冊以上の技術書を執筆した。直近では、「大規模言語モデルを使いこなすためのプロンプトエンジニアリングの教科書(マイナビ出版)」「Pythonでつくるデスクトップアプリ(ソシム)」「実践力を身につける Pythonの教科書 第2版」「シゴトがはかどる Python自動処理の教科書(マイナビ出版)」など。





