Come posso creare un file zip / tgz in Linux in modo che Windows abbia nomi di file corretti?


26

Attualmente tar -zcf arch.tgz files/*codifica i nomi dei file in UTF, quindi gli utenti Windows vedono tutti i caratteri rovinati nei nomi dei file che non sono inglesi e non possono farci nulla.

zip -qq -r arch.zip files/* ha lo stesso comportamento.

Come posso creare un archivio zip / tgz in modo che quando gli utenti di Windows lo estraggono avranno tutti i nomi di file codificati correttamente?

Risposte:


24

Attualmente tar codifica i nomi dei file in UTF

In realtà tar non codifica / decodifica i nomi dei file, li copia semplicemente dal filesystem così com'è. Se la tua locale è basata su UTF-8 (come in molte distro Linux moderne), sarà UTF-8. Sfortunatamente la codepage di sistema di una finestra di Windows non è mai UTF-8, quindi i nomi saranno sempre alterati tranne che su strumenti come WinRAR che consentono di modificare il set di caratteri utilizzato.

Quindi è impossibile creare un file ZIP con nomi di file non ASCII che funzionano attraverso le versioni di Windows di diversi paesi e il loro supporto per le cartelle compresse integrate.

È un difetto dei formati tar e zip che non ci sono informazioni di codifica fisse o fornite, quindi i caratteri non ASCII saranno sempre non portatili. Se hai bisogno di un formato di archivio non ASCII, dovrai utilizzare uno dei formati più recenti, come 7z o rar recenti. Sfortunatamente questi sono ancora traballanti; in 7zip è necessario l' -mcuinterruttore e raramente non utilizzerà UTF-8 a meno che non rilevi caratteri non presenti nella tabella codici.

Fondamentalmente è un casino orribile e se riesci a evitare di distribuire archivi contenenti nomi di file con caratteri non ASCII, starai molto meglio.


Grazie mille! Sfortunatamente, la maggior parte degli utenti non sa nulla di 7z e rar è proprietario :(
kolypto

Sì, è un problema. ZIP è di gran lunga la soluzione più utilizzabile per gli utenti, poiché tutti i sistemi operativi moderni hanno un buon supporto dell'interfaccia utente nativa. Sfortunatamente il problema dei set di caratteri non è davvero risolvibile oggi in ZIP (e anche in altri formati di archivio è ancora problematico).
bobince,

25

Ecco un semplice script Python che ho scritto per decomprimere i file tar da UNIX su Windows:

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()

Eccezionale! questo script mi ​​ha aiutato a convertire un file tar codificato EUC-JP che è stato creato su un vecchio server Solaris.
wm_eddie,

Signore, mi ha salvato la vita. Dio ti benedica :)
user1576772

8

Il problema, usando in Linux il default tar(GNU tar), viene risolto ... aggiungendo il --format=posixparametro durante la creazione del file.

Per esempio:
tar --format=posix -cf

In Windows, per estrarre i file, uso bsdtar .

In https://lists.gnu.org/archive/html/bug-tar/2005-02/msg00018.html è scritto (dal 2005 !!):

> Ho letto qualcosa nel ChangeLog su UTF-8 supportato. Cosa significa
> questo?
> Non ho trovato il modo di creare un archivio che fosse intercambiabile
> tra diverse localizzazioni.

Quando si creano archivi in ​​formato POSIX.1-2001 (tar --format = posix o --format = pax), tar converte i nomi dei file dalle impostazioni locali correnti in UTF-8 e quindi li memorizza nell'archivio. Durante l'estrazione, viene eseguita l'operazione inversa.

PS Invece di digitare --format=posixè possibile digitare -H pax, che è più breve.


5

Credo che tu stia riscontrando problemi con il formato contenitore Zip stesso. Il catrame potrebbe soffrire dello stesso problema.

Utilizzare invece i formati di archivio 7zip ( .7z) o RAR ( .rar). Entrambi sono disponibili per Windows e Linux; il p7zipsoftware gestisce entrambi i formati.

Ho appena testato creando .7z, .rar, .zip, e .tarfile su entrambi WinXP e Debian 5, e l' .7ze .rarmemorizzare i file / ripristinare i nomi di file in modo corretto, mentre l' .zipe .tarfile non fanno. Non importa quale sistema viene utilizzato per creare l'archivio di prova.


5

Ho avuto problemi con il disimballaggio tare i zipfile che ricevo dagli utenti Windows. Mentre non rispondo alla domanda "come creare l'archivio che funzionerà", gli script seguenti aiutano a decomprimere tare ziparchiviare correttamente indipendentemente dal sistema operativo originale.

ATTENZIONE: è necessario ottimizzare manualmente la codifica sorgente ( cp1251, cp866negli esempi seguenti). Le opzioni della riga di comando potrebbero essere una buona soluzione in futuro.

Catrame:

#!/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()

Cerniera lampo:

#!/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 : Uso il chardetpacchetto per indovinare la codifica corretta del blocco di dati non elaborato . Ora la sceneggiatura funziona immediatamente su tutti i miei archivi danneggiati, oltre a quelli buoni.

Cose da notare:

  1. Tutti i nomi di file vengono estratti e uniti nella singola stringa per creare un pezzo più grande di testo per il motore di indovinare la codifica. Significa che pochi nomi di file avvitati in modo diverso possono rovinare l'ipotesi.
  2. È stato utilizzato un percorso rapido speciale per gestire un buon testo Unicode ( chardetnon funziona con un normale oggetto Unicode).
  3. I doctest vengono aggiunti per testare e dimostrare che il normalizzatore riconosce qualsiasi codifica su stringhe ragionevolmente brevi.

Versione finale:

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

Grazie per i tuoi programmi! Purtroppo, il programma Zip non funziona con Python 3, ma funziona con Python 2.
beroal

@beroal, ho aggiornato lo script. Ora utilizza il motore sviluppato da Mozilla per Firefox per il rilevamento automatico della codifica.
dmitry_romanov

4

POSIX-1.2001 ha specificato come TAR utilizza UTF-8.

A partire dal 2007, la versione del registro delle modifiche 6.3.0 in PKZIP APPNOTE.TXT ( http://www.pkware.com/documents/casestudies/APPNOTE.TXT ) ha specificato come ZIP utilizza UTF-8.

È solo quali strumenti supportano correttamente questi standard, che rimane una domanda aperta.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.