Как извлечь файл в папке внутри ZIP?

Мне нужно извлечь файл с именем Preview.pdf из папки с именем QuickLooks внутри zip-файла.

Прямо сейчас мой код выглядит примерно так:

with ZipFile(newName, 'r') as newName:
        newName.extract(\QuickLooks\Preview.pdf)
        newName.close()

(В этом случае, newName был установлен равным полному пути к почтовому индексу).

Важно отметить, что обратная косая черта в этом случае верна, потому что я на Windows.

Код не работает; вот ошибка, которую это дает:

Traceback (most recent call last):
  File "C:\Users\Asit\Documents\Evam\Python_Scripts\pageszip.py", line 18, in <module>
    ZF.extract("""QuickLooks\Preview.pdf""")
  File "C:\Python33\lib\zipfile.py", line 1019, in extract
    member = self.getinfo(member)
  File "C:\Python33\lib\zipfile.py", line 905, in getinfo
    'There is no item named %r in the archive' % name)
KeyError: "There is no item named 'QuickLook/Preview.pdf' in the archive"

Я запускаю скрипт Python из Notepad++ и беру вывод из его консоли.

Как я могу сделать это?

Кроме того, как я могу извлечь всю папку QuickLooks, переместить Preview.pdf, а затем удалить папку и остальное ее содержимое?

Просто для контекста, вот остальная часть сценария. Это скрипт для получения PDF файла.pages. Я знаю, что есть блаженные конвертеры там; Я просто делаю это в качестве упражнения с каким-то реальным приложением.

import os.path
import zipfile
from zipfile import *
import sys

file = raw_input('Enter the full path to the .pages file in question. Please note that file and directory names cannot contain any spaces.')
dir = os.path.abspath(os.path.join(file, os.pardir))
fileName, fileExtension = os.path.splitext(file)
if fileExtension == ".pages":
    os.chdir(dir)
    print (dir)
    fileExtension = ".zip"
    os.rename (file, fileName + ".zip")
    newName = fileName + ".zip"  #for debugging purposes
    print (newName) #for debugging purposes
    with ZipFile(newName, 'w') as ZF:
        print("I'm about to list names!")
        print(ZF.namelist()) #for debugging purposes
        ZF.extract("QuickLook/Preview.pdf")
    os.rename('Preview.pdf', fileName + '.pdf')
    finalPDF = fileName + ".pdf"
    print ("Check out the PDF! It's located at" + dir +  finalPDF + ".")
else:
    print ("Sorry, this is not a valid .pages file.")
    sys.exit

Я не уверен, если импорт Zipfile является избыточным; Я прочитал на другом посте SO, что это было лучше использовать from zipfile import * чем import zipfile, Я не был уверен, поэтому я использовал оба. знак равно

РЕДАКТИРОВАТЬ: я изменил код, чтобы отразить изменения, предложенные Blckknght.

1 ответ

Решение

Вот кое-что, что, кажется, работает. Было несколько проблем с вашим кодом. Как я уже упоминал в комментарии, zip-файл должен быть открыт в режиме 'r', чтобы прочитать его. Другое - имена членов zip-архива всегда используют косую черту / символы в их путевых именах в качестве разделителей (см. раздел 4.4.17.1 Замечания по применению PKZIP). Важно знать, что нет способа извлечь вложенный элемент архива в другой подкаталог с текущей версией Python.zipfileмодуль. Вы можете управлять корневым каталогом, но ничего под ним (т.е. любые подпапки внутри zip).

Наконец, поскольку нет необходимости переименовывать файл.pages в.zip - имя файла, который вы передаетеZipFile() может иметь любое расширение - я удалил все это из кода. Однако, чтобы преодолеть ограничение на извлечение элементов в другой подкаталог, мне пришлось добавить код, чтобы сначала извлечь целевой элемент во временный каталог, а затем скопировать его в конечный пункт назначения. После этого, конечно, эту временную папку нужно удалить. Так что я не уверен, что чистый результат намного проще...

import os.path
import shutil
import sys
import tempfile
from zipfile import ZipFile

PREVIEW_PATH = 'QuickLooks/Preview.pdf'  # archive member path
pages_file = input('Enter the path to the .pages file in question: ')
#pages_file = r'C:\Stack Overflow\extract_test.pages'  # hardcode for testing
pages_file = os.path.abspath(pages_file)
filename, file_extension = os.path.splitext(pages_file)
if file_extension == ".pages":
    tempdir = tempfile.gettempdir()
    temp_filename = os.path.join(tempdir, PREVIEW_PATH)
    with ZipFile(pages_file, 'r') as zipfile:
        zipfile.extract(PREVIEW_PATH, tempdir)
    if not os.path.isfile(temp_filename):  # extract failure?
        sys.exit('unable to extract {} from {}'.format(PREVIEW_PATH, pages_file))
    final_PDF = filename + '.pdf'
    shutil.copy2(temp_filename, final_PDF)  # copy and rename extracted file
    # delete the temporary subdirectory created (along with pdf file in it)
    shutil.rmtree(os.path.join(tempdir, os.path.split(PREVIEW_PATH)[0]))
    print('Check out the PDF! It\'s located at "{}".'.format(final_PDF))
    #view_file(final_PDF)  # see Bonus below
else:
    sys.exit('Sorry, that isn\'t a .pages file.')

Бонус: если вы хотите на самом деле просмотреть окончательный файл PDF из скрипта, вы можете добавить следующую функцию и использовать ее в конечном созданном PDF-файле (при условии, что в вашей системе установлено приложение для просмотра PDF):

import subprocess
def view_file(filepath):
    subprocess.Popen(filepath, shell=True).wait()
Другие вопросы по тегам