J'ai eu des problèmes avec le déballage tar
et les zip
fichiers que je reçois des utilisateurs de Windows. Bien que je ne réponde pas à la question "comment créer l'archive qui fonctionnera", les scripts ci-dessous aident à décompresser tar
et à classer les zip
fichiers correctement quel que soit le système d'exploitation d'origine.
ATTENTION: il faut régler la source codant manuellement ( cp1251
, cp866
dans les exemples ci - dessous). Les options de ligne de commande peuvent être une bonne solution à l'avenir.
Le goudron:
#!/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()
Zip *: français:
#!/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 : J'utilise le chardet
package pour deviner l'encodage correct du bloc de données brut. Maintenant, le script fonctionne hors de la boîte sur toutes mes mauvaises archives, ainsi que les bonnes.
À noter:
- Tous les noms de fichiers sont extraits et fusionnés dans la chaîne unique pour faire une plus grande partie du texte pour le moteur de devinette d'encodage. Cela signifie que peu de noms de fichiers vissés d'une manière différente peuvent gâcher la supposition.
- Un raccourci spécial a été utilisé pour gérer un bon texte Unicode (
chardet
ne fonctionne pas avec un objet Unicode normal).
- Des tests sont ajoutés pour tester et démontrer que le normalisateur reconnaît tout encodage sur des chaînes raisonnablement courtes.
Version 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."