如何在zip中的文件夹中提取文件?

Posted

技术标签:

【中文标题】如何在zip中的文件夹中提取文件?【英文标题】:How to extract a file within a folder within a zip? 【发布时间】:2014-03-04 01:25:00 【问题描述】:

我需要从 zip 文件中名为 QuickLooks 的文件夹中提取一个名为 Preview.pdf 的文件。

现在我的代码看起来有点像这样:

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

(在这种情况下,newName 已设置为等于 zip 的完整路径)。

请务必注意,在这种情况下反斜杠是正确的,因为我使用的是 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"

我在 Notepad++ 中运行 Python 脚本,并从其控制台获取输出。

我怎样才能做到这一点?

另外,我如何提取整个 QuickLooks 文件夹,移出 Preview.pdf,然后删除该文件夹及其其余内容?

仅出于上下文考虑,这是脚本的其余部分。这是一个获取 .pages 文件的 PDF 的脚本。我知道那里有 Bonified 转换器。我只是将其作为某种实际应用程序的练习。

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 建议的更改。

【问题讨论】:

您正在打开要写入的文件,而 ZipFile(newName, 'w') 未读取。 @martineau 谢谢!我修好了。 @martineau 值得将其添加为答案,以便可以通过解决方案对其进行检查。 @LegoStormtroopr 我还没有真正尝试过这个脚本......我会尝试并告诉你。 它没有解决问题... 【参考方案1】:

这似乎可行。您的代码有几个问题。正如我在评论中提到的,压缩文件必须以模式“r”打开才能阅读。另一个是 zip 存档成员名称总是在其路径名称中使用正斜杠 / 字符作为分隔符(参见 PKZIP Application Note 的第 4.4.17.1 节)。请务必注意,无法使用 Python 的 currentzipfilemodule 将嵌套存档成员提取到不同的子目录中。您可以控制根目录,但不能控制根目录(即 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()

【讨论】:

shutil.rmtree(os.path.join(tempdir, os.path.split(PREVIEW_PATH)[0]))print('Check out the PDF! It\'s located at "".'.format(final_PDF)) 行是做什么的? rmtree() 调用删除了通过提取 preview.pdf 文件创建的临时子目录。它通过使用拆分PREVIEW_PATH的第一部分得到目录名称,这导致QuickLooks,然后将临时目录路径加入到它以获得它的完整路径。 format() 是使用其字符串作为格式化规范或模式的字符串方法。在线documentation中描述了这两个功能。

以上是关于如何在zip中的文件夹中提取文件?的主要内容,如果未能解决你的问题,请参考以下文章

使用 python zipfile 提取 zip 子文件夹中的文件

从 Python3 中的 .zip 文件中提取和读取 [重复]

从 zip 文件中提取子文件

无论 Django 中的模板更改(或发生其他外部问题)如何,在后台提取大型 zip 文件的最佳方法是啥?

访问 .zip 存档中的文件而不提取它们

如何在不提取Java的情况下读取压缩文件的内容