回答:
現在、tarはファイル名をUTFでエンコードします
実際、tarはファイル名をまったくエンコード/デコードせず、ファイルシステムからそのままコピーします。ロケールがUTF-8ベースの場合(最近の多くのLinuxディストリビューションのように)、UTF-8になります。残念ながら、WindowsボックスのシステムコードページはUTF-8ではないため、WinRARなどの文字セットを変更できるツールを除き、名前は常にマングルされます。
そのため、異なる国のリリースのWindowsで機能する非ASCIIファイル名のZIPファイルを作成したり、組み込みの圧縮フォルダーをサポートしたりすることはできません。
tarおよびzip形式の欠点は、固定または提供されたエンコード情報がないため、非ASCII文字は常に非ポータブルであることです。非ASCIIアーカイブ形式が必要な場合は、最近の7zやrarなどの新しい形式のいずれかを使用する必要があります。残念ながら、これらはまだ不安定です。7zipでは-mcu
スイッチが必要です。コードページにない文字を検出しない限り、rarはUTF-8を使用しません。
基本的にそれは恐ろしい混乱であり、非ASCII文字を含むファイル名を含むアーカイブの配布を避けることができれば、はるかに良いでしょう。
これは、Windows上のUNIXからtarファイルを展開するために書いた簡単なPythonスクリプトです。
import tarfile
archive_name = "archive_name.tar"
def recover(name):
return unicode(name, 'utf-8')
tar = tarfile.open(name=archive_name, mode='r', bufsize=16*1024)
updated = []
for m in tar.getmembers():
m.name = recover(m.name)
updated.append(m)
tar.extractall(members=updated)
tar.close()
Linuxでデフォルトtar
(GNU tar)を使用している問題は解決されました... --format=posix
ファイルの作成時にパラメーターを追加します。
例えば:
tar --format=posix -cf
Windowsでは、ファイルを抽出するためにbsdtarを使用します。
でhttps://lists.gnu.org/archive/html/bug-tar/2005-02/msg00018.htmlそれは(以降書かれている2005年!):
> ChangeLogで、UTF-8がサポートされていることを読みました。何が行い
、この平均値>?
>
異なるロケール間で互換性のあるアーカイブを作成する方法が見つかりませんでした。POSIX.1-2001形式(tar --format = posixまたは--format = pax)でアーカイブを作成する場合、tarはファイル名を現在のロケールからUTF-8に変換し、アーカイブに保存します。抽出するとき、逆の操作が実行されます。
PS入力--format=posix
する代わりに、-H pax
より短いを入力できます。
Zipコンテナ形式自体に問題が発生していると思います。タールも同じ問題に苦しんでいる可能性があります。
代わりに7zip(.7z
)またはRAR(.rar
)アーカイブ形式を使用してください。どちらもWindowsとLinuxで利用可能です。p7zip
ソフトウェアは、両方のフォーマットを処理します。
私はちょうど作成テスト.7z
、.rar
、.zip
、と.tar
WinXPのとDebian 5、および両方のファイル.7z
と.rar
しながら、ファイルストアは/正しくファイル名を復元.zip
し、.tar
ファイルがありません。テストアーカイブの作成に使用されるシステムは関係ありません。
Windowsユーザーから受け取ったファイルの展開tar
とzip
ファイルに問題がありました。「動作するアーカイブを作成する方法」という質問には答えませんが、以下のスクリプトは元のOSに関係なく、正しく解凍tar
してzip
ファイルを作成するのに役立ちます。
警告:一つは(チューニングを手動でコード化されたソースを有するcp1251
、cp866
以下の実施例で)。コマンドラインオプションは、将来的には良い解決策になるかもしれません。
タール:
#!/usr/bin/env python
import tarfile
import codecs
import sys
def recover(name):
return codecs.decode(name, 'cp1251')
for tar_filename in sys.argv[1:]:
tar = tarfile.open(name=tar_filename, mode='r', bufsize=16*1024)
updated = []
for m in tar.getmembers():
m.name = recover(m.name)
updated.append(m)
tar.extractall(members=updated)
tar.close()
郵便番号:
#!/usr/bin/env python
import zipfile
import os
import codecs
import sys
def recover(name):
return codecs.decode(name, 'cp866')
for filename in sys.argv[1:]:
archive = zipfile.ZipFile(filename, 'r')
infolist = archive.infolist()
for i in infolist:
f = recover(i.filename)
print f
if f.endswith("/"):
os.makedirs(os.path.dirname(f))
else:
open(f, 'w').write(archive.read(i))
archive.close()
UPD 2018-01-02:chardet
パッケージを使用して、生のデータチャンクの正しいエンコーディングを推測します。これで、スクリプトは、すべての悪いアーカイブと良いアーカイブですぐに動作します。
注意事項:
chardet
通常のUnicodeオブジェクトでは機能しません)。最終版:
#!/usr/bin/env python2
# coding=utf-8
import zipfile
import os
import codecs
import sys
import chardet
def make_encoding_normalizer(txt):
u'''
Takes raw data and returns function to normalize encoding of the data.
* `txt` is either unicode or raw bytes;
* `chardet` library is used to guess the correct encoding.
>>> n_unicode = make_encoding_normalizer(u"Привет!")
>>> print n_unicode(u"День добрый")
День добрый
>>> n_cp1251 = make_encoding_normalizer(u"Привет!".encode('cp1251'))
>>> print n_cp1251(u"День добрый".encode('cp1251'))
День добрый
>>> type(n_cp1251(u"День добрый".encode('cp1251')))
<type 'unicode'>
'''
if isinstance(txt, unicode):
return lambda text: text
enc = chardet.detect(txt)['encoding']
return lambda file_name: codecs.decode(file_name, enc)
for filename in sys.argv[1:]:
archive = zipfile.ZipFile(filename, 'r')
infolist = archive.infolist()
probe_txt = "\n".join(i.filename for i in infolist)
normalizer = make_encoding_normalizer(probe_txt)
for i in infolist:
print i.filename
f = normalizer(i.filename)
print f
dirname = os.path.dirname(f)
if dirname:
assert os.path.abspath(dirname).startswith(os.path.abspath(".")), \
"Security violation"
if not os.path.exists(dirname):
os.makedirs(dirname)
if not f.endswith("/"):
open(f, 'w').write(archive.read(i))
archive.close()
if __name__ == '__main__' and len(sys.argv) == 1:
# Hack for Python 2.x to support unicode source files as doctest sources.
reload(sys)
sys.setdefaultencoding("UTF-8")
import doctest
doctest.testmod()
print "If there are no messages above, the script passes all tests."
POSIX-1.2001は、TARがUTF-8を使用する方法を指定しました。
2007年の時点で、PKZIP APPNOTE.TXT(http://www.pkware.com/documents/casestudies/APPNOTE.TXT)のchangelogバージョン6.3.0では、ZIPでのUTF-8の使用方法が指定されていました。
どのツールがこれらの標準を適切にサポートするかだけが、未解決の問題です。