Здравствуйте! В настоящее время я работаю над инструментом, который должен извлечь некоторые файлы .tar.
Он прекрасно работает по большей части, но у меня есть одна проблема:
Некоторые файлы .tar и .zip имеют имена, содержащие "недопустимые" символы (f.ex ":"). Эта программа должна работать на машинах с Windows, поэтому мне приходится иметь дело с этим.
Есть ли способ, которым я могу изменить имя некоторых файлов в извлеченном выводе, если он содержит ":" или другой недопустимый символ Windows.
Моя текущая реализация:
def read_zip(filepath, extractpath):
with zipfile.ZipFile(filepath, 'r') as zfile:
contains_bad_char = False
for finfo in zfile.infolist():
if ":" in finfo.filename:
contains_bad_char = True
if not contains_bad_char:
zfile.extractall(path=extractpath)
def read_tar(filepath, extractpath):
with tarfile.open(filepath, "r:gz") as tar:
contains_bad_char = False
for member in tar.getmembers():
if ":" in member.name:
contains_bad_char = True
if not contains_bad_char:
tar.extractall(path=extractpath)
Так что в настоящее время я просто игнорирую все эти результаты, что не идеально.
Чтобы лучше описать, о чем я прошу, приведу небольшой пример:
file_with_files.tar -> small_file_1.txt
-> small_file_2.txt
-> annoying:file_1.txt
-> annoying:file_1.txt
Следует извлечь в
file_with_files -> small_file_1.txt
-> small_file_2.txt
-> annoying_file_1.txt
-> annoying_file_1.txt
Является ли единственным решением перебирать каждый файлобъект в сжатом файле и извлекать его по одному или есть более элегантное решение?
Согласно [Python 3]: ZipFile. Извлечь (член, путь = Нет, pwd = Нет):
В Windows недопустимые символы (
:
,<
,>
,|
,"
,?
И*
) заменяются подчеркиванием (_
).
Итак, все уже решено:
>>> import os >>> import zipfile >>> >>> os.getcwd() 'e:\\Work\\Dev\\StackOverflow\\q055340013' >>> os.listdir() ['arch.zip'] >>> >>> zf = zipfile.ZipFile("arch.zip") >>> zf.namelist() ['file0.txt', 'file:1.txt'] >>> zf.extractall() >>> zf.close() >>> >>> os.listdir() ['arch.zip', 'file0.txt', 'file_1.txt']
Быстрый просмотр по tarfile (source и doc) не выявил ничего подобного (и я не был бы очень удивлен, если бы этого не было, так как формат .tar в основном используется в Nix), поэтому вам придется это сделать вручную. Все не так просто, как я ожидал, поскольку tarfile не предлагает возможность извлечения члена под другим именем, как это делает zipfile.
Во всяком случае, здесь кусок кода (у меня были zipfile и tarfile в качестве муз или источников вдохновения):
def read_tar(filepath, extractpath="."):
win_illegal = ':<>|"?*'
table = str.maketrans(win_illegal, '_' * len(win_illegal))
with tarfile.open(filepath, "r:gz") as tar:
for member in tar.getmembers():
if member.isdir():
os.makedirs(member.path.translate(table))
else:
with open(os.path.join(extractpath, member.path.translate(table)), "wb") as fout:
fout.write(tarfile.ExFileObject(tar, member).read())
Обратите внимание, что приведенный выше код работает для простых файлов .tar (с простыми элементами, включая каталоги), но я не проверял его на надежность.
@EDIT0:
Добавлена обработка каталогов.
@EDIT1:
Отправлено [Python.Bugs]: tarfile: обработка недопустимых символов Windows (путь) в именах членов архива.
Я не знаю, каковы будут его результаты, поскольку я представил несколько вопросов (и исправлений для них), которые были более серьезными (на моем PoV), но по разным причинам они были отклонены.