現在、 tar -zcf Arch.tgz files/*
は、ファイル名をUTFでエンコードするため、Windowsユーザーは、ファイル名に書きこまれたすべての文字英語ではないを表示し、それを使用して何もできません。
Zip -qq -r Arch.Zip files/*
も同じ動作です。
Windowsユーザーが解凍したときにすべてのファイル名が適切にエンコードされるように、Zip/tgzアーカイブを作成するにはどうすればよいですか?
現在、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!!):
>サポートされているUTF-8について、ChangeLogで何かを読みました。なに
>これはどういう意味ですか?
>互換性のあるアーカイブを作成する方法が見つからなかった
>異なるロケール間。POSIX.1-2001形式(tar --format = posixまたは--format = pax)でアーカイブを作成する場合、tarはファイル名を現在のロケールからUTF-8に変換してからアーカイブに保存します。抽出時は逆の操作を行います。
追伸--format=posix
と入力する代わりに、短い[-H pax
]と入力できます。
Zipコンテナー形式自体に問題が発生していると思います。タールも同じ問題に苦しんでいる可能性があります。
代わりに 7Zip (.7z
)またはRAR(.rar
)アーカイブ形式を使用してください。どちらもWindowsとLinuxで使用できます。 p7Zip
ソフトウェアは両方の形式を処理します。
WinXPとDebian 5の両方で.7z
、.rar
、.Zip
、.tar
ファイル、および.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()
PD 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を使用する方法を指定しています。
これらの標準を適切にサポートするのはこのツールだけであり、未解決の問題です。