如何从.gz存档中获取原始文件的名称

  • 本文关键字:文件 原始 获取 gz python gzip
  • 更新时间 :
  • 英文 :


>我正在编写一个实用程序,该实用程序采用.gz存档并检查其内容是否已存在于指定的文件夹中。如果他们不这样做,它将提取那里的存档。

我计划这样做的方法是逐个读取.gz存档中文件的文件名,并检查我的目录中是否已存在此类文件。但据我了解,这在 gzip 上是不可能的。

理想情况下,我正在寻找这样的东西:

archive = gzipfile.GzipFile(source)
    for i in archive.getmembers():
        if os.path.isfile(destination + sep + i.name) and overwrite:
        ...

这可能吗?

虽然.gz文件确实只是一个压缩文件,但原始文件名可以被截断,或者实际上压缩的.gz文件可以被重命名。 可以告诉gunzip使用 -N 标志提供原始文件名,如果与 -l(减去小写 L)一起使用,它将告诉您原始文件名而无需解压缩文件。
例如:

$ gzip sometext.txt
$ mv sometext.txt.gz othertext.gz
$ gunzip -Nl othertext.gz
         compressed        uncompressed  ratio uncompressed_name
                 58                 113  76.1% sometext.txt

你也可以在python中破解它。

from subprocess import check_output
size_name = check_output(['gunzip', '-Nlq','othertext.gz'])
size_name = size_name.strip().split("%",1)
print "original filename =",size_name[1].strip()

结果:

original filename = sometext.txt

我不相信python gzip包允许您访问原始文件名。
别人可能知道不同!

添加到接受的答案:

至少CPython的gzip不会公开文件名元数据,因为它只是丢弃了它,正如您在检查源代码时所看到的那样。

但是,gzip 文件格式(在 RFC 1952 中指定)或至少其元数据很容易手动解析:

import struct
def getGzipName(path):
    with open(path, 'rb') as file:
        id1, id2, compression, flags, mtime, extraFlags, osId = struct.unpack('<BBBBLBB', file.read(10))
        if id1 != 0x1F or id2 != 0x8B or compression != 0x08:
            return None
        # Extra Field (e.g. used by bgzip to store the length of the compressed block)
        if flags & ( 1 << 2 ) != 0:
            file.read(struct.unpack('<U', file.read(2))[0])
        # File Name Field
        if flags & ( 1 << 3 ) != 0:
            name = b''
            c = file.read(1)
            while c != b'':
                name += c
                c = file.read(1)
            return name.decode()
    return None

请注意,理论上 gzip 可以用作存档格式,因为它确实支持存储原始文件名,可用于存储路径,并且允许多个 gzip 流(都具有不同的文件名)相互连接。但是,即使是gzip工具也不支持这种异国情调的 gzip 文件,即使没有--name选项。它只是将第二个 gzip 流的数据连接到第一个 gzip 流的原始文件名。

.gz文件不是存档,它只是被压缩。如果您有.tar.gz文件,则可以使用 tarfile

import tarfile
archive = tarfile.open(source)
for i in archive.getmembers():
    ...

相关内容

最新更新