Извлечение файлов из zip без сохранения структуры с использованием python ZipFile?
Я пытаюсь извлечь все файлы из .zip, содержащие подпапки в одной папке. Я хочу, чтобы все файлы из подпапок извлекались только в одной папке без сохранения исходной структуры. На данный момент я извлекаю все, перемещаю файлы в папку, а затем удаляю предыдущие подпапки. Файлы с одинаковыми именами перезаписываются.
Возможно ли это сделать до написания файлов?
Вот структура, например:
my_zip/file1.txt
my_zip/dir1/file2.txt
my_zip/dir1/dir2/file3.txt
my_zip/dir3/file4.txt
В конце я этого хочу:
my_dir/file1.txt
my_dir/file2.txt
my_dir/file3.txt
my_dir/file4.txt
Что я могу добавить в этот код?
import zipfile
my_dir = "D:\\Download\\"
my_zip = "D:\\Download\\my_file.zip"
zip_file = zipfile.ZipFile(my_zip, 'r')
for files in zip_file.namelist():
zip_file.extract(files, my_dir)
zip_file.close()
Если я переименую путь к файлам из zip_file.namelist(), у меня есть эта ошибка:
KeyError: "There is no item named 'file2.txt' in the archive"
Ответы
Ответ 1
Это открывает дескрипторы файлов членов zip-архива, извлекает имя файла и копирует его в целевой файл (что работает ZipFile.extract
, не заботясь о подкаталогах).
import os
import shutil
import zipfile
my_dir = r"D:\Download"
my_zip = r"D:\Download\my_file.zip"
with zipfile.ZipFile(my_zip) as zip_file:
for member in zip_file.namelist():
filename = os.path.basename(member)
# skip directories
if not filename:
continue
# copy file (taken from zipfile extract)
source = zip_file.open(member)
target = file(os.path.join(my_dir, filename), "wb")
with source, target:
shutil.copyfileobj(source, target)
Ответ 2
Просто извлеките в байты в памяти, вычислите имя файла и напишите его там сами,
вместо того, чтобы позволить библиотеке сделать это - почти, просто используйте "read()" вместо метода "extract()":
import zipfile
import os
my_dir = "D:\\Download\\"
my_zip = "D:\\Download\\my_file.zip"
zip_file = zipfile.ZipFile(my_zip, 'r')
for files in zip_file.namelist():
data = zip_file.read(files, my_dir)
# I am almost shure zip represents directory separator
# char as "/" regardless of OS, but I don't have DOS or Windos here to test it
myfile_path = os.path.join(my_dir, files.split("/")[-1])
myfile = open(myfile_path, "wb")
myfile.write(data)
myfile.close()
zip_file.close()
Ответ 3
Можно выполнить итерацию по ZipFile.infolist()
. На возвращенных объектах ZipInfo
вы можете затем обработать filename
, чтобы удалить часть каталога и, наконец, извлечь его в указанный каталог.
import glob
import zipfile
import shutil
import os
my_dir = "D:\\Download\\"
my_zip = "D:\\Download\\my_file.zip"
with zipfile.ZipFile(my_zip) as zip:
for zip_info in zip.infolist():
if zip_info.filename[-1] == '/':
continue
zip_info.filename = os.path.basename(zip_info.filename)
zip.extract(zip_info, my_dir)
Ответ 4
В случае, если вы получаете ошибку badZipFile. Вы можете распаковать архив, используя 7zip sub process. при условии, что вы установили 7zip, используйте следующий код.
import subprocess
my_dir = destFolder #destination folder
my_zip = destFolder + "/" + filename.zip #file you want to extract
ziploc = "C:/Program Files/7-Zip/7z.exe" #location where 7zip is installed
cmd = [ziploc, 'e',my_zip ,'-o'+ my_dir ,'*.txt' ,'-r' ]
#extracting only txt files and from all subdirectories
sp = subprocess.Popen(cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)