LinuxでWindowsが適切なファイル名を持つようにzip / tgzを作成するにはどうすればよいですか?


26

現在、tar -zcf arch.tgz files/*ファイル名はUTF でエンコードされているため、Windowsユーザーは、英語以外のファイル名台無しにされたすべての文字を表示し、何もできません。

zip -qq -r arch.zip files/* 同じ動作をします。

zip / tgzアーカイブを作成して、Windowsユーザーが抽出したときにすべてのファイル名が適切にエンコードされるようにするにはどうすればよいですか?

回答:


24

現在、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文字を含むファイル名を含むアーカイブの配布を避けることができれば、はるかに良いでしょう。


まことにありがとうございます!残念ながら、ほとんどのユーザーは7zについて何も知らず、rarは独自のものです:(
kolypto

ええ、それは問題です。最新のすべてのOSにはZIPがネイティブUIでサポートされているため、ZIPはユーザーにとって最も使いやすいソリューションです。残念ながら、文字セットの問題は現在、ZIPで実際に解決することはできません(他のアーカイブ形式でさえ、まだ面倒です)。
ボビンス

25

これは、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()

驚くばかり!このスクリプトは、古いSolarisサーバーで作成されたEUC-JPエンコードされたtarファイルを変換するのに役立ちました。
wm_eddie

サー、あなたは私の命を救った。神のご
加護

8

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より短いを入力できます。


5

Zipコンテナ形式自体に問題が発生していると思います。タールも同じ問題に苦しんでいる可能性があります。

代わりに7zip.7z)またはRAR(.rar)アーカイブ形式を使用してください。どちらもWindowsとLinuxで利用可能です。p7zipソフトウェアは、両方のフォーマットを処理します。

私はちょうど作成テスト.7z.rar.zip、と.tarWinXPのとDebian 5、および両方のファイル.7z.rarしながら、ファイルストアは/正しくファイル名を復元.zipし、.tarファイルがありません。テストアーカイブの作成に使用されるシステムは関係ありません。


5

Windowsユーザーから受け取ったファイルの展開tarzipファイルに問題がありました。「動作するアーカイブを作成する方法」という質問には答えませんが、以下のスクリプトは元のOSに関係なく、正しく解凍tarしてzipファイルを作成するのに役立ちます。

警告:一つは(チューニングを手動でコード化されたソースを有するcp1251cp866以下の実施例で)。コマンドラインオプションは、将来的には良い解決策になるかもしれません。

タール:

#!/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-02chardetパッケージを使用して、生のデータチャンクの正しいエンコーディングを推測します。これで、スクリプトは、すべての悪いアーカイブと良いアーカイブですぐに動作します。

注意事項:

  1. すべてのファイル名が抽出され、単一の文字列にマージされて、エンコーディング推測エンジン用の大きなテキストが作成されます。それは、それぞれ異なる方法でねじ込まれたいくつかのファイル名が推測を台無しにする可能性があることを意味します。
  2. 適切なUnicodeテキストを処理するために、特別な高速パスが使用されました(chardet通常のUnicodeオブジェクトでは機能しません)。
  3. Doctestsは、ノーマライザーが適度に短い文字列のエンコードを認識することをテストおよび実証するために追加されています。

最終版:

#!/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."

あなたのプログラムをありがとう!残念ながら、ZipプログラムはPython 3では動作しませんが、Python 2では動作します。
beroal

@beroal、スクリプトを更新しました。Firefox向けにMozillaが開発したエンジンを使用して、エンコードを自動検出するようになりました。
dmitry_romanov

4

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の使用方法が指定されていました。

どのツールがこれらの標準を適切にサポートするかだけが、未解決の問題です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.