Note There is no official file name encoding for ZIP files. If you have unicode file names, you must convert them to byte strings in your desired encoding before passing them to write(). WinZip interprets all file names as encoded in CP437, also known as DOS Latin.
-# if fname != zinfo.orig_filename.encode("utf-8"): - if fname != zinfo.orig_filename.encode("utf-8" if zinfo.flag_bits & 0x800 else "cp437"): + if fname != zinfo.orig_filename.encode("utf-8"):
raise BadZipfile(
'File name in directory %r and header %r differ.'
% (zinfo.orig_filename, fname))
UNICODE文字列に起因する問題 (スコア:3, 参考になる)
zipファイル形式の圧縮/伸張ライブラリzipfile.ZipFileで、ファイル名エンコーディングがUTF-8決めうちになってしまったようです。
従来のzipfile.ZipFile.writeは、zipに格納されるファイル名に8ビット文字列をそのまま使っていたため、エンコーディングを自分で選ぶことができました。
(とゆーか、ライブラリ側が関知するところではなかった(^^;))
しかし、Python3.0からはUNICODE文字列で与える形式となり、かつ今のところエンコーディングを変更することはできないみたい。 # ↑こうすると、Windowsでは解凍時にファイル名が文字化け。
# WindowsではShift_JIS(CP932)が一般的なので。
元々zipファイルはファイル名エンコーディングに問題を含んでいて、MacOSXで圧縮したzipをWindows側で解凍するとファイル名が文字化けするといったことが起きていたわけですけど、これがPython3.0で表面化してしまった感じですねー。
仕方ないので、zipfileを使っていたところをtarfileに置き換えて修正を進めてます。
標準がUNICODE文字列であることは実際便利で、今までエンコーディング変換で手間をかけていたところがすっきり書けるのは良いんですけど、しばらくは様々な問題が頻出しそうな予感がします。
Re:UNICODE文字列に起因する問題 (スコア:1)
Re: (スコア:0)
Note
There is no official file name encoding for ZIP files. If you have unicode file names, you must convert them to byte strings in your desired encoding before passing them to write(). WinZip interprets all file names as encoded in CP437, also known as DOS Latin.
って書いてあるけど、これってファイルネームを自分でエンコードしたbytesで渡せってことだよね。
未確認だけどこれでできないの?
Re:UNICODE文字列に起因する問題 (スコア:2, 参考になる)
3.0の zipfile.py を参照すると、圧縮時はまず 'ascii' でエンコードしてみて、例外が出るようなら 'utf-8' で再度エンコードします。(zipfile.py:335)
# このときフラグ(0x800)を立てているようですが、Vistaエクスプローラ/Lhplus/+Lhaca等の解凍ツールはチェックしてないみたいで、いずれもUTF-8は文字化けしちゃいます。
解凍時はフラグを見て、0x800が立っていたら 'utf-8'、そうでなければ 'cp437' でファイル名をデコードします。(zipfile.py:759)
つまり、cp437(DOS-US)だけは正常に解凍できるという極悪仕様(^^;)
Re: (スコア:0)
いや、3.0でも同じですね。
ということは、仕様というよりは実装の問題ですから、言えばすぐに直されるんじゃないでしょうか。
Re:UNICODE文字列に起因する問題 (スコア:2, 参考になる)
ただ、現実問題として「すぐに直せる」レベルかどうかは少し微妙かもです。
ちょっと今は試せないんですが(作業が残っているため、まだ自宅マシンには導入できない(^^;))、3.0からは文字列がUNICODEになってしまった(8ビットの方はバイト列扱いのbytes型になった)ので、多分ですが中でエンコード/デコードが必要になってくると思われます。
現状だとファイル名エンコーディングを明示するインターフェースがZipFileに存在しないため、仕様を追加しないと対応は難しいんじゃないかと。
そもそもは現状の、「zip内ファイル名エンコーディングが環境依存」という状況が良くないんですよね……。
どのみちOSX等とのやり取りで支障を来しているので、私はこの際zipを捨ててtar.gzに移行する予定です(^^;)
Re: (スコア:0)
ないでしょうが、この手の問題は他にもいろいろな場面ででてきそうですね。
一つの対処法としてstrやbytesのメンバーとしてencodingを設定できるようにするのは
どうだろう。これなら意図したとおりに変換できるし、自動変換させればstrとbytesを
演算可能にもできる。
zipfileで非utf-8ファイル名のファイルを解凍するための最小限のハック (スコア:1, 参考になる)
+++ Python-3.0/root/usr/local/lib/python3.0/zipfile.py 2008-12-06 10:50:20.000000000 +0900
@@ -877,8 +877,7 @@
if fheader[_FH_EXTRA_FIELD_LENGTH]:
zef_file.read(fheader[_FH_EXTRA_FIELD_LENGTH])
-# if fname != zinfo.orig_filename.encode("utf-8"):
- if fname != zinfo.orig_filename.encode("utf-8" if zinfo.flag_bits & 0x800 else "cp437"):
+ if fname != zinfo.orig_filename.encode("utf-8"):
raise BadZipfile(
'File name in directory %r and header %r differ.'
% (zinfo.orig_filename, fname))
のは完全なミスでしょう。
あとはファイル名に関しては
filename = info.filename
else:
filename = info.filename.encode('cp437').decode('cp932')
今回3.0を使ってみて、bytesとstrの互換性の無さが気になった。
'abc'+b'123'やb'asd'.index('s')がエラーになるのは使いにくい。
Re: (スコア:0)
appnote [pkware.com]のAPPENDIX D - Language Encoding (EFS)に従っただけですね。確かに cp437 だけってのは互換性に対する配慮が足りないという気はしますが、Java の java.util.zip みたいにフラグも立てずに utf-8 で出力するよりはマシだと思います。
Re: (スコア:0)
Re: (スコア:0)
>ファイル名エンコーディングがUTF-8決めうちになってしまったようです。
それってjarファイルじゃないですか。
しかし、思ったのはやっぱりリリースされてから
試さない人がいるから、それなりの品質でもリリースしてしまった方がいいんだなぁ、ということ。
# MSはよく分かってる