ฉันมีปัญหากับการแกะกล่องtar
และzip
ไฟล์ที่ฉันได้รับจากผู้ใช้ Windows ในขณะที่ฉันไม่ตอบคำถาม "วิธีสร้างที่เก็บถาวรซึ่งจะใช้งานได้" สคริปต์ด้านล่างช่วยในการคลายไฟล์tar
และzip
ไฟล์อย่างถูกต้องโดยไม่คำนึงถึงระบบปฏิบัติการดั้งเดิม
คำเตือน: หนึ่งที่มีการปรับแต่งแหล่งที่เข้ารหัสด้วยตนเอง ( cp1251
, cp866
ในตัวอย่างด้านล่าง) ตัวเลือกบรรทัดคำสั่งอาจเป็นทางออกที่ดีในอนาคต
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()
ไปรษณีย์:
#!/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 : ฉันใช้chardet
แพ็คเกจเพื่อคาดเดาการเข้ารหัสที่ถูกต้องของกลุ่มข้อมูลดิบ ตอนนี้สคริปต์ทำงานนอกกรอบในคลังเก็บข้อมูลที่ไม่ดีทั้งหมดของฉันรวมถึงคลังเก็บที่ดี
สิ่งที่ควรทราบ:
- ชื่อไฟล์ทั้งหมดจะถูกแยกและรวมเข้าไปในสายเดียวเพื่อสร้างข้อความที่ใหญ่ขึ้นสำหรับเอ็นจิ้นการเดารหัส หมายความว่าชื่อไฟล์บางส่วนถูกเมาในวิธีที่ต่างกันซึ่งแต่ละอย่างอาจทำให้การเดาผิด
- พา ธ ด่วนพิเศษใช้เพื่อจัดการกับข้อความยูนิโค้ดที่ดี (
chardet
ไม่สามารถทำงานกับวัตถุ Unicode ปกติ)
- มีการเพิ่ม Doctests เพื่อทดสอบและเพื่อแสดงให้เห็นว่า Normalizer จดจำการเข้ารหัสใด ๆ ในสตริงที่สั้นพอสมควร
รุ่นสุดท้าย:
#!/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."