Tôi gặp vấn đề với việc giải nén tar
và zip
các tệp tôi nhận được từ người dùng Windows. Mặc dù tôi không trả lời câu hỏi "làm thế nào để tạo kho lưu trữ sẽ hoạt động", các tập lệnh bên dưới giúp giải nén tar
và zip
tập tin chính xác bất kể HĐH gốc.
CẢNH BÁO: người ta phải điều chỉnh mã hóa nguồn theo cách thủ công ( cp1251
, cp866
trong các ví dụ bên dưới). Tùy chọn dòng lệnh có thể là một giải pháp tốt trong tương lai.
Tar:
#!/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:
#!/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()
CẬP NHẬT 2018-01 / 02 : Tôi sử dụng chardet
gói để đoán mã hóa chính xác của khối dữ liệu thô. Bây giờ kịch bản hoạt động tốt trên tất cả các tài liệu lưu trữ xấu của tôi, cũng như một tài liệu tốt.
Những điều cần lưu ý:
- Tất cả các tên tệp được trích xuất và hợp nhất thành một chuỗi để tạo ra một đoạn văn bản lớn hơn cho công cụ đoán mã hóa. Điều đó có nghĩa là một vài tên tập tin được gắn vào một cách khác nhau, mỗi tên có thể làm hỏng dự đoán.
- Đường dẫn nhanh đặc biệt được sử dụng để xử lý văn bản unicode tốt (
chardet
không hoạt động với một đối tượng unicode bình thường).
- Doctests được thêm vào để kiểm tra và để chứng minh rằng bộ chuẩn hóa nhận ra bất kỳ mã hóa nào trên một chuỗi ngắn hợp lý.
Phiên bản cuối cùng:
#!/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."