我有一个.gz
文件,我需要使用python获取其中的文件名。
此问题与github
相同唯一的区别是我的文件是.gz
而不是.tar.gz
所以tarfile
库在这里没有帮助我
我正在使用requests
库来请求网址。响应是压缩文件。
以下是我用来下载文件的代码
response = requests.get(line.rstrip(), stream=True)
if response.status_code == 200:
with open(str(base_output_dir)+"/"+str(current_dir)+"/"+str(count)+".gz", 'wb') as out_file:
shutil.copyfileobj(response.raw, out_file)
del response
此代码下载名称为1.gz
的文件。现在,如果我使用存档管理器打开文件,该文件将包含my_latest_data.json
我需要提取文件,输出为my_latest_data.json
。
以下是我用来提取文件的代码
inF = gzip.open(f, 'rb')
outfilename = f.split(".")[0]
outF = open(outfilename, 'wb')
outF.write(inF.read())
inF.close()
outF.close()
outputfilename
变量是我在脚本中提供的字符串,但我需要真实的文件名(my_latest_data.json
)
答案 0 :(得分:4)
你不能,因为Gzip不是档案格式。
这本身就是一个垃圾解释,所以让我打破这个比我在评论中做的更多......
只是压缩
“只是一个压缩系统”意味着Gzip对输入字节(通常来自文件)进行操作并输出压缩字节。你不知道里面的字节是代表多个文件还是只代表一个文件 - 它只是 一个已压缩的字节流。这就是为什么你可以通过网络接受gzip压缩数据的原因。其bytes_in - > bytes_out。
什么是清单?
清单是存档中的标题,用作存档的目录。请注意,现在我使用术语“归档”而不是“压缩的字节流”。归档意味着它是清单引用的文件或段的集合 - 压缩的字节流只是一个字节流。
Gzip中有什么内容?
.gz文件内容的简化描述是:
就是这样。没有明显。
另一方面,存档格式将在内部显示清单。这就是tar库的用武之地.Tar只是一种将一堆位拼凑成一个文件的方法,并在前面放置一个清单,让你知道原始文件的名称以及它们之前的大小。连接到存档。因此,.tar.gz
如此普遍。
有些实用程序允许您一次解压缩gzip压缩文件的某些部分,或者仅在内存中解压缩它,然后让您检查清单或其中可能存在的内容。但任何清单的详细信息都特定于其中包含的存档格式。
请注意,这与 zip 存档不同。 Zip 是一种存档格式,因此包含一个清单。 Gzip是一个压缩库,比如bzip2和朋友。
答案 1 :(得分:3)
使用Mark Adler回复中的提示和对gzip模块的一些检查我已经设置了这个从gzip文件中提取内部文件名的功能。我注意到GzipFile对象有一个名为_read_gzip_header()的私有方法,几乎得到了文件名,所以我根据它做了
import gzip
def get_gzip_filename(filepath):
f = gzip.open(filepath)
f._read_gzip_header()
f.fileobj.seek(0)
f.fileobj.read(3)
flag = ord(f.fileobj.read(1))
mtime = gzip.read32(f.fileobj)
f.fileobj.read(2)
if flag & gzip.FEXTRA:
# Read & discard the extra field, if present
xlen = ord(f.fileobj.read(1))
xlen = xlen + 256*ord(f.fileobj.read(1))
f.fileobj.read(xlen)
filename = ''
if flag & gzip.FNAME:
while True:
s = f.fileobj.read(1)
if not s or s=='\000':
break
else:
filename += s
return filename or None
答案 2 :(得分:1)
正如另一个答案所述,你的问题只有在我取出复数时才有意义:“我有一个.gz
文件,我需要在里面找到文件的名字它使用python。“
gzip标头中可能包含也可能没有文件名。 gzip实用程序通常会忽略标头中的名称,并解压缩到与.gz
文件同名的文件,但剥离.gz
。例如。您的1.gz
会解压缩到名为1
的文件,即使标头中包含文件名my_latest_data.json
也是如此。 gzip的-N选项将使用标题中的文件名(以及标题中的时间戳),如果有的话。因此gzip -dN 1.gz
会创建文件my_latest_data.json
,而不是1
。
您可以通过手动处理标题在Python的标题中找到文件名。您可以在gzip specification。
中找到详细信息1f 8b 08
。flags
。如果flags & 8
为零,则放弃 - 标题中没有文件名。flags & 2
不为零,则跳过两个字节。flags & 4
不为零,则读取接下来的两个字节。考虑到它们是以小端序排列,从这两个字节中取出一个整数,称之为xlen
。然后跳过xlen
个字节。flags & 8
不为零,因此您现在处于文件名。读取字节直到达到零字节。这些字节最多但不包括零字节是文件名。答案 3 :(得分:1)
The Python 3 gzip
library discards this information 但你可以采用链接周围的代码来做其他事情。
如本页其他答案所述,此信息无论如何都是可选的。但是,如果您需要查看它是否在那里,也不是不可能检索。
import struct
def gzinfo(filename):
# Copy+paste from gzip.py line 16
FTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT = 1, 2, 4, 8, 16
with open(filename, 'rb') as fp:
# Basically copy+paste from GzipFile module line 429f
magic = fp.read(2)
if magic == b'':
return False
if magic != b'\037\213':
raise ValueError('Not a gzipped file (%r)' % magic)
method, flag, _last_mtime = struct.unpack("<BBIxx", fp.read(8))
if method != 8:
raise ValueError('Unknown compression method')
if flag & FEXTRA:
# Read & discard the extra field, if present
extra_len, = struct.unpack("<H", fp.read(2))
fp.read(extra_len)
if flag & FNAME:
fname = []
while True:
s = fp.read(1)
if not s or s==b'\000':
break
fname.append(s.decode('latin-1'))
return ''.join(fname)
def main():
from sys import argv
for filename in argv[1:]:
print(filename, gzinfo(filename))
if __name__ == '__main__':
main()
这用模糊的 ValueError
异常替换了原始代码中的异常(如果您打算更广泛地使用它,您可能需要修复它,并将其转换为合适的模块,您可以import
) 并使用通用的 read()
函数而不是特定的 _read_exact()
方法,该方法经历了一些麻烦,以确保它得到它所请求的确切字节数(如果您愿意,也可以取消) .