使用Python的GZIP模块

23

我想使用Python GZIP模块来解压缩一个目录中的多个.gz文件,注意,我不想读取这些文件,只是要解压它们。在这个网站上搜索了一段时间后,我得到了以下代码段,但它并不能正常工作:

import gzip
import glob
import os
for file in glob.glob(PATH_TO_FILE + "/*.gz"):
    #print file
    if os.path.isdir(file) == False:
        shutil.copy(file, FILE_DIR)
        # uncompress the file
        inF = gzip.open(file, 'rb')
        s = inF.read()
        inF.close()

.gz文件已经放在正确的位置,我可以使用print命令打印出完整的路径+文件名,但是GZIP模块没有正确执行。我缺少了什么吗?


文件没问题吗?你没有展示发生了什么或者没有发生什么。 - f p
是的,文件没问题。我可以在UNIX命令行上使用gunzip解压缩该文件。 - user3111358
5个回答

40

如果您没有收到错误信息,则gzip模块可能已经成功执行,并且文件已经被解压缩

"解压缩"的确切定义取决于上下文:

我只想要解压缩文件, 而不是读取它们

gzip模块不能像7-zip这样作为桌面归档程序工作 - 您无法在"读取"文件之前"解压缩"它。请注意,在编程中,“读取”通常只意味着“将其(暂时)存储在计算机RAM中”,而不是“在GUI中打开该文件”。

您可能所说的"解压缩"(如桌面归档程序) 更精确地描述为(在编程中) "从一个压缩文件读取内存流/缓冲区,并将其写入一个新文件(并可能删除压缩文件)"

inF = gzip.open(file, 'rb')
s = inF.read()
inF.close()

通过这些代码,你只是读取文件流。如果你想创建一个新的“未压缩”文件,你只需要将缓存区写入一个新文件即可

with open(out_filename, 'wb') as out_file:
    out_file.write(s)

如果你需要处理非常大的文件(大于你的内存容量),你需要采用不同的方法。但这是另一个问题的话题。


当我运行Python脚本时没有出现错误,但gzip文件没有被解压缩。我只想解压缩文件以便另一个工具可以使用它,而不是将其重写到文件中或在脚本中其他地方使用。 - user3111358
1
@user3111358,您所说的“gzip文件未解压缩”是什么意思?您为什么这么说?您是否检查了代码中s的内容? - loopbackbee
我的意思是gzip文件没有被解压缩,这就是我想要做的。我只想解压缩,仅此而已。 - user3111358
3
我想说的是,“解压缩”在不同的上下文中有不同的含义。我猜如果你问一些在Stack Overflow上读过你的代码的人,他们会告诉你这个文件确实被解压了。因此,我必须问:你是怎么知道这个文件没有被“解压缩”的?是因为当你运行代码时,与压缩文件放在同一个目录下没有新文件被放置吗? - loopbackbee
这是正确的答案。解压文件时,它会被写入一个新文件,之前的压缩文件则被删除或者保留为原始压缩文件。无论哪种方式,都会生成一个新的未压缩文件。 - sage88

6

打开文件并读取压缩文件的结果,建议使用with。可以参考gzip文档

import gzip
import glob
import os
import os.path

for gzip_path in glob.glob("%s/*.gz" % PATH_TO_FILE):
    if not os.path.isdir(gzip_path):
        with gzip.open(gzip_path, 'rb') as in_file:
            s = in_file.read()

        # Now store the uncompressed data
        path_to_store = gzip_fname[:-3]  # remove the '.gz' from the filename

        # store uncompressed file data from 's' variable
        with open(path_to_store, 'w') as f:
            f.write(s)

根据你想要做的事情的具体情况,你可能需要查看tarfile及其'r:gz'选项来打开文件。


最好使用 os.path.splitext(gzip_fname)[0] 来删除 .gz 扩展名。 - gotson
您的示例是错误的,gzip_fname 不存在,您必须将其更改为 gzip_path。此外,您获得的内容不是路径,而是 gz 文件。因此,您应该将 os.path.isdir 更改为 os.path.isfile。我认为使用 @gotson 的解决方案更好 :) - hoaphumanoid

6
你正在将文件解压到s变量中,并且没有对其进行任何操作。你应该停止在stackoverflow上搜索并至少阅读Python教程。说真的。

无论如何,你的代码有几个问题:

  1. 你需要将s中的未压缩数据存储到某个文件中。

  2. 没有必要复制实际的*.gz文件。因为在你的代码中,你正在解压原始gzip文件而不是副本。

  3. 你正在使用保留字file作为变量。这不是一个错误,只是一种非常糟糕的做法。

这应该可以实现你想要的:

import gzip
import glob
import os
import os.path

for gzip_path in glob.glob(PATH_TO_FILE + "/*.gz"):
    if os.path.isdir(gzip_path) == False:
        inF = gzip.open(gzip_path, 'rb')
        # uncompress the gzip_path INTO THE 's' variable
        s = inF.read()
        inF.close()

        # get gzip filename (without directories)
        gzip_fname = os.path.basename(gzip_path)
        # get original filename (remove 3 characters from the end: ".gz")
        fname = gzip_fname[:-3]
        uncompressed_path = os.path.join(FILE_DIR, fname)

        # store uncompressed file data from 's' variable
        open(uncompressed_path, 'w').write(s)

当您调用open(uncompressed_path, 'w').write(s)而不将文件处理器分配给变量时,是否不需要关闭文件处理器? - Ander
1
@Ander - 是的,因为(匿名)文件对象永远不会被分配给变量,因此在执行后立即被销毁。对于简单的“将xy写入文件”或“从文件读取”,我认为这更加清晰 - 即当确切地有一个读取或写入时。但是,如果您进行多次读取/写入,则应该始终使用with open(...): - Jan Spurny

4
我使用subprocess模块解决了这个问题:
for file in glob.glob(PATH_TO_FILE + "/*.gz"):
    if os.path.isdir(file) == False:
        shutil.copy(file, FILE_DIR)
        # uncompress the file
        subprocess.call(["gunzip", FILE_DIR + "/" + os.path.basename(file)])

由于我的目标只是解压缩存档,上面的代码已经实现了这个目标。存档文件位于一个中心位置,被复制到工作区域,进行解压操作,并在测试用例中使用。GZIP模块对我所需的功能过于复杂。

感谢大家的帮助,非常感激!


是的,如果您不需要以编程方式操作代码内容,并且不介意它在操作系统之间不可互用,那么这是一种更直观的方法来处理事情。 - ChrisGuest

0

我认为有一个比其他提出的解决方案更简单的解决方案,因为操作者只想从目录中提取所有文件:

import glob
from setuptools import archive_util

for fn in glob.glob('*.gz'):
  archive_util.unpack_archive(fn, '.')

3
Archive_util.unpack_archive 似乎不支持 .gz 格式的文件。错误消息是 "setuptools.archive_util.UnrecognizedFormat: Not a recognized archive type: K:\z_temp\file.gz"。另外 shutil.unpack_archive 也不支持 .gz 格式的文件。要查看 shutil_unpack_archive 支持的文件类型,请运行以下代码:import shutil; print(shutil.get_archive_formats()) - punchcard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接