Wie kann ich unter Linux ein zip / tgz erstellen, damit Windows richtige Dateinamen hat?

28442
kolypto

Derzeit werden tar -zcf arch.tgz files/*Dateinamen in UTF codiert. Windows-Benutzer sehen also alle Zeichen, deren Dateinamen nicht englisch sind, und können damit nichts anfangen.

zip -qq -r arch.zip files/* hat das gleiche Verhalten.

Wie kann ich ein zip / tgz-Archiv erstellen, damit alle Dateinamen beim Entpacken von Windows ordnungsgemäß codiert werden?

25

6 Antworten auf die Frage

25
Alexei Osipov

Hier ist ein einfaches Python-Skript, das ich geschrieben habe, um Tar-Dateien von UNIX unter Windows zu entpacken:

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() 
Genial! Dieses Skript half mir beim Konvertieren einer EUC-JP-codierten TAR-Datei, die auf einem alten Solaris-Server erstellt wurde. wm_eddie vor 13 Jahren 0
Sir, Sie haben mein Leben gerettet. Gott schütze dich :) user1576772 vor 8 Jahren 0
24
bobince

Derzeit codiert tar Dateinamen in UTF

Tatsächlich codiert / decodiert tar keine Dateinamen, sondern kopiert sie einfach aus dem Dateisystem, so wie sie sind. Wenn Ihr Gebietsschema UTF-8-basiert ist (wie in vielen modernen Linux-Distributionen), ist dies UTF-8. Leider ist die System-Codepage einer Windows-Box niemals UTF-8, daher werden die Namen immer geändert, außer bei Tools wie WinRAR, mit denen der verwendete Zeichensatz geändert werden kann.

Daher ist es nicht möglich, eine ZIP-Datei mit Nicht-ASCII-Dateinamen zu erstellen, die für die verschiedenen Windows-Versionen von Windows und deren integrierte Unterstützung für komprimierte Ordner geeignet ist.

Ein Nachteil der tar- und zip-Formate ist, dass es keine festen oder angegebenen Codierungsinformationen gibt. Daher sind Nicht-ASCII-Zeichen immer nicht portierbar. Wenn Sie ein Nicht-ASCII-Archivformat benötigen, müssen Sie eines der neueren Formate verwenden, z. B. die letzten 7z- oder rar-Dateien. Leider sind diese immer noch unklar. in 7zip benötigen Sie den -mcuSchalter, und rar verwendet UTF-8 erst dann, wenn Zeichen erkannt werden, die nicht in der Codepage enthalten sind.

Im Grunde ist es ein schreckliches Durcheinander, und wenn Sie es vermeiden können, Archive zu verteilen, die Dateinamen mit Nicht-ASCII-Zeichen enthalten, ist dies viel besser.

Vielen Dank! Leider wissen die meisten Benutzer nichts über 7z und rar ist proprietär :( kolypto vor 14 Jahren 0
Ja, das ist ein Problem. ZIP ist bei weitem die am besten verwendbare Lösung für Benutzer, da alle modernen Betriebssysteme über eine native native Benutzeroberflächenunterstützung verfügen. Leider ist das Zeichensatzproblem heute in ZIP nicht wirklich lösbar (und selbst in anderen Archivformaten ist es immer noch problematisch). bobince vor 14 Jahren 0
8
Sys

The problem, using in Linux the default tar (GNU tar), is solved... adding the --format=posix parameter when creating the file.

For example:
tar --format=posix -cf

In Windows, to extract the files, I use bsdtar.

In https://lists.gnu.org/archive/html/bug-tar/2005-02/msg00018.html it is written (since 2005!!):

> I read something in the ChangeLog about UTF-8 being supported. What does
> this mean?
> I found no way to create an archive that would be interchangeable
> between different locales.

When creating archives in POSIX.1-2001 format (tar --format=posix or --format=pax), tar converts file names from the current locales to UTF-8 and then stores them in archive. When extracting, the reverse operation is performed.

P.S. Instead of typing --format=posix you can type -H pax, which is shorter.

5
quack quixote

Ich glaube, dass Sie Probleme mit dem ZIP-Containerformat selbst haben. Teer kann an demselben Problem leiden.

Verwenden Sie stattdessen die Archivformate 7zip ( .7z) oder RAR ( .rar). Beide sind für Windows und Linux verfügbar. Die p7zipSoftware verarbeitet beide Formate.

Ich Schaffung gerade getestet .7z, .rar, .zip, und .tarDateien sowohl auf WinXP und Debian 5 und die .7zund .rarDateien speichern / wiederherstellen Dateinamen korrekt, während die .zipund .tarDateien nicht. Es ist egal, mit welchem ​​System das Testarchiv erstellt wird.

4
damjan

POSIX-1.2001 hat angegeben, wie TAR UTF-8 verwendet.

Seit 2007 wurde in der Änderungsprotokoll-Version 6.3.0 in PKZIP APPNOTE.TXT ( http://www.pkware.com/documents/casestudies/APPNOTE.TXT ) festgelegt, wie ZIP UTF-8 verwendet.

Nur welche Tools diese Standards richtig unterstützen, bleibt eine offene Frage.

4
dmitry_romanov

Ich hatte Probleme beim Entpacken tarund zipDateien, die ich von Windows-Benutzern erhalten habe. Während ich die Frage "Wie erstellt man ein Archiv, das funktionieren wird" nicht beantwortet wird, helfen die nachstehenden Skripts beim Entpacken tarund der zipkorrekten Dateien, unabhängig vom ursprünglichen Betriebssystem.

ACHTUNG: man muss manuell die Quellencodierung abzustimmen ( cp1251, die cp866in den Beispielen unten). Befehlszeilenoptionen können in Zukunft eine gute Lösung sein.

Teer:

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

Postleitzahl:

#!/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 : Ich verwende chardetPaket, um die korrekte Kodierung des rohen Datenblocks zu erraten. Jetzt funktioniert das Skript in allen meinen schlechten Archiven sofort und in einem guten.

Dinge zu beachten:

  1. Alle Dateinamen werden extrahiert und in die einzelne Zeichenfolge eingefügt, um einen größeren Textteil für die Codierungs-Schätz-Engine zu erstellen. Dies bedeutet, dass nur wenige Dateinamen, die auf unterschiedliche Weise verschraubt werden, die Vermutung stören können.
  2. Ein spezieller Fast-Path wurde verwendet, um einen guten Unicode-Text zu verarbeiten ( chardetfunktioniert nicht mit einem normalen Unicode-Objekt).
  3. Doctests werden hinzugefügt, um zu testen und zu demonstrieren, dass der Normalisierer jede Codierung auf einer relativ kurzen Zeichenfolge erkennt.

Endgültige Version:

#!/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." 
Vielen Dank für Ihre Programme! Leider funktioniert das Zip-Programm nicht unter Python 3, aber es funktioniert unter Python 2. beroal vor 6 Jahren 0
@beroal, ich habe das Skript aktualisiert. Jetzt wird die von Mozilla für Firefox entwickelte Engine verwendet, um die Kodierung automatisch zu erkennen. dmitry_romanov vor 6 Jahren 0