如何从 .gz 存档中获取原始文件的名称?
How to get the name of the original file from a .gz archive?
我正在编写一个实用程序,它获取 .gz 存档并检查其内容是否已存在于指定文件夹中。如果他们不这样做,它将在那里提取存档。
我计划这样做的方法是一个一个地读取 .gz 存档中文件的文件名,并检查我的目录中是否已经存在这样的文件。但据我所知,gzip 是不可能的。
理想情况下,我正在寻找这样的东西:
archive = gzipfile.GzipFile(source)
for i in archive.getmembers():
if os.path.isfile(destination + sep + i.name) and overwrite:
...
这可能吗?
import tarfile
archive = tarfile.open(source)
for i in archive.getmembers():
...
.gz
文件不是存档,它只是被压缩了。如果你有一个 .tar.gz
文件,你可以使用 tarfile
.
虽然 .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
不会公开文件名元数据,因为它 simply discards it 正如您在检查源代码时所看到的那样。
但是,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'[=10=]':
name += c
c = file.read(1)
return name.decode()
return None
请注意,理论上 gzip 可以用作存档格式,因为它确实支持存储原始文件名,这可能用于存储路径,并且因为多个 gzip 流(所有具有不同文件名的文件)允许相互连接。然而,即使 gzip
工具也不支持这种奇异的 gzip 文件,即使使用 --name
选项也是如此。它会简单地将第二个 gzip 流的数据连接到第一个 gzip 流的原始文件名。
我正在编写一个实用程序,它获取 .gz 存档并检查其内容是否已存在于指定文件夹中。如果他们不这样做,它将在那里提取存档。
我计划这样做的方法是一个一个地读取 .gz 存档中文件的文件名,并检查我的目录中是否已经存在这样的文件。但据我所知,gzip 是不可能的。
理想情况下,我正在寻找这样的东西:
archive = gzipfile.GzipFile(source)
for i in archive.getmembers():
if os.path.isfile(destination + sep + i.name) and overwrite:
...
这可能吗?
import tarfile
archive = tarfile.open(source)
for i in archive.getmembers():
...
.gz
文件不是存档,它只是被压缩了。如果你有一个 .tar.gz
文件,你可以使用 tarfile
.
虽然 .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
不会公开文件名元数据,因为它 simply discards it 正如您在检查源代码时所看到的那样。
但是,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'[=10=]':
name += c
c = file.read(1)
return name.decode()
return None
请注意,理论上 gzip 可以用作存档格式,因为它确实支持存储原始文件名,这可能用于存储路径,并且因为多个 gzip 流(所有具有不同文件名的文件)允许相互连接。然而,即使 gzip
工具也不支持这种奇异的 gzip 文件,即使使用 --name
选项也是如此。它会简单地将第二个 gzip 流的数据连接到第一个 gzip 流的原始文件名。