我试图读取一个 gz 文件:
with open(os.path.join(storage_path,file), "rb") as gzipfile:
with gzip.GzipFile(fileobj=gzipfile) as datafile:
data = datafile.read()
它有效,但我需要包含在我的 gz 文件中的每个文件的文件名和大小。此代码将包含文件的内容打印到存档中。
如何读取此 gz 文件中包含的文件名?
我试图读取一个 gz 文件:
with open(os.path.join(storage_path,file), "rb") as gzipfile:
with gzip.GzipFile(fileobj=gzipfile) as datafile:
data = datafile.read()
它有效,但我需要包含在我的 gz 文件中的每个文件的文件名和大小。此代码将包含文件的内容打印到存档中。
如何读取此 gz 文件中包含的文件名?
Pythongzip
模块不提供对该信息的访问。
源代码跳过它而不存储它:
if flag & FNAME:
# Read and discard a null-terminated string containing the filename
while True:
s = self.fileobj.read(1)
if not s or s=='\000':
break
文件名组件是可选的,不保证存在(我认为,在这种情况下,命令行gzip -c
解压缩选项将使用原始文件名 sans )。.gz
未压缩的文件大小不存储在标头中;您可以在最后四个字节中找到它。
要自己从标题中读取文件名,您需要重新创建文件标题读取代码,并保留文件名字节。以下函数返回它,加上解压缩后的大小:
import struct
from gzip import FEXTRA, FNAME
def read_gzip_info(gzipfile):
gf = gzipfile.fileobj
pos = gf.tell()
# Read archive size
gf.seek(-4, 2)
size = struct.unpack('<I', gf.read())[0]
gf.seek(0)
magic = gf.read(2)
if magic != '\037\213':
raise IOError('Not a gzipped file')
method, flag, mtime = struct.unpack("<BBIxx", gf.read(8))
if not flag & FNAME:
# Not stored in the header, use the filename sans .gz
gf.seek(pos)
fname = gzipfile.name
if fname.endswith('.gz'):
fname = fname[:-3]
return fname, size
if flag & FEXTRA:
# Read & discard the extra field, if present
gf.read(struct.unpack("<H", gf.read(2)))
# Read a null-terminated string containing the filename
fname = []
while True:
s = gf.read(1)
if not s or s=='\000':
break
fname.append(s)
gf.seek(pos)
return ''.join(fname), size
将上述函数与已创建的gzip.GzipFile
对象一起使用:
filename, size = read_gzip_info(gzipfileobj)
GzipFile 本身没有这些信息,但是:
.gz
In [14]: f = open('fuse-ext2-0.0.7.tar.gz')
In [15]: f.seek(-4, 2)
In [16]: import struct
In [17]: r = f.read()
In [18]: struct.unpack('<I', r)[0]
Out[18]: 7106560
In [19]: len(gzip.open('fuse-ext2-0.0.7.tar.gz').read())
Out[19]: 7106560
(从技术上讲,最后四个字节是原始(未压缩)输入数据模 2 32的大小(成员预告片中的 ISIZE 字段,http: //www.gzip.org/zlib/rfc-gzip.html ))
我已经在这种模式下解决了:
fl = search_files(storage_path)
for f in fl:
with open(os.path.join(storage_path,f), "rb") as gzipfile:
with gzip.GzipFile(fileobj=gzipfile) as datafile:
data = datafile.read()
print str(storage_path) + "/" + str(f[:-3]) + " : " + str(len(data)) + " bytes" #pcap file size
我不知道这是否正确。
有什么建议吗?
新代码:
fl = search_files(storage_path)
for f in fl:
with open(os.path.join(storage_path,f), "rb") as gzipfile:
#try with module 2^32
gzipfile.seek(-4,2)
r = gzipfile.read()
print str(storage_path) + "/" + str(f[:-3]) + " : " + str(struct.unpack('<I' ,r)[0]) + " bytes" #dimensione del file pcap
Martjin的解决方案真的很不错,我已经为Python 3.6+打包了:https ://github.com/PierreSelim/gzinfo
只是需要pip install gzinfo
在你的代码中
import gzinfo
info = gzinfo.read_gz_info('bar.txt.gz')
# info.name is 'foo.txt'
print(info.fname)