我是python的新手,我在将tarfile的内容读入python时遇到了麻烦。
数据是一篇期刊文章的内容(托管在pubmed central),请参见下面的信息,并链接到我想读入Python的tarfile。
http://www.pubmedcentral.nih.gov/utils/oa/oa.fcgi?id=PMC13901ftp://ftp.ncbi.nlm.nih.gov/pub/pmc/b0/ac/Breast_Cancer_Res_2001_Nov_9_3(1)_61-65.tar.gz
我有一个类似的. tar.gz文件的列表,我最终也会想读进去。我认为(知道)所有的tarfiles都有一个. nxml文件与它们相关联。这是我实际上感兴趣的. nxml文件的内容。欢迎对最佳方式的任何建议...
如果我把tarfile保存到我的pc上,下面是我所得到的。所有运行都如预期。
tarfile_name = "F:/PMC_OA_TextMining/Breast_Cancer_Res_2001_Nov_9_3(1)_61-65.tar.gz"
tfile = tarfile.open(tarfile_name)
tfile_members = tfile.getmembers()
tfile_members1 = []
for i in range(len(tfile_members)):
tfile_members_name = tfile_members[i].name
tfile_members1.append(tfile_members_name)
tfile_members2 = []
for i in range(len(tfile_members1)):
if tfile_members1[i].endswith('.nxml'):
tfile_members2.append(tfile_members1[i])
tfile_extract1 = tfile.extractfile(tfile_members2[0])
tfile_extract1_text = tfile_extract1.read()
我今天了解到,为了直接从pubmed centrals FTP站点访问tarfile,我必须使用urllib
设置一个网络请求。下面是修改后的代码(以及我收到的stackoverflow应答的链接):
Read contents of .tar.gz file from website into a python 3.x object
tarfile_name = "ftp://ftp.ncbi.nlm.nih.gov/pub/pmc/b0/ac/Breast_Cancer_Res_2001_Nov_9_3(1)_61-65.tar.gz"
ftpstream = urllib.request.urlopen(tarfile_name)
tfile = tarfile.open(fileobj=ftpstream, mode="r|gz")
然而,当我运行剩下的代码时(如下),我得到了一个错误消息("不允许向后搜索")。
tfile_members = tfile.getmembers()
tfile_members1 = []
for i in range(len(tfile_members)):
tfile_members_name = tfile_members[i].name
tfile_members1.append(tfile_members_name)
tfile_members2 = []
for i in range(len(tfile_members1)):
if tfile_members1[i].endswith('.nxml'):
tfile_members2.append(tfile_members1[i])
tfile_extract1 = tfile.extractfile(tfile_members2[0])
tfile_extract1_text = tfile_extract1.read()
代码在最后一行失败,我尝试读取与我的tarfile关联的. nxml内容。下面是我收到的实际错误消息。它意味着什么?读取/访问这些嵌入在tarfile中的. nxml文件的内容的最佳解决方案是什么?
Traceback (most recent call last):
File "F:\PMC_OA_TextMining\test2.py", line 135, in <module>
tfile_extract1_text = tfile_extract1.read()
File "C:\Python30\lib\tarfile.py", line 804, in read
buf += self.fileobj.read()
File "C:\Python30\lib\tarfile.py", line 715, in read
return self.readnormal(size)
File "C:\Python30\lib\tarfile.py", line 722, in readnormal
self.fileobj.seek(self.offset + self.position)
File "C:\Python30\lib\tarfile.py", line 531, in seek
raise StreamError("seeking backwards is not allowed")
tarfile.StreamError: seeking backwards is not allowed
提前感谢你的帮助。克里斯
4条答案
按热度按时间7gcisfzg1#
**问题:**Tar文件是交错存储的。它们的顺序是header,data,header,data,header,data,data,etc。当你用
getmembers()
枚举文件时,你已经读了整个文件以获得头文件。然后当你要求tarfile对象读取数据时,它试图从最后一个头文件向后搜索到第一个数据。但是如果你不关闭并重新打开urllib请求,你就不能在网络流中向后搜索。**解决方法:**您需要下载文件,将临时副本保存到磁盘或StringIO,枚举此临时副本中的文件,然后解压缩所需的文件。
abithluo2#
tl;dr:删除
getmembers
以保留流这是一个非常古老的问题,但答案与大多数遇到这个问题的人想要的答案***截然不同。
如果你有一个流媒体源,你几乎肯定希望在你的模式中使用管道操作符(比如
r|
):假设整个文件是一个时间轴,其中
X
标记您的当前位置,*
标记您要读取的第一个文件X---*------
getmembers
,它需要读取整个tar来告诉你所有文件的位置,所以现在你的位置在文件的末尾:---*------X
extractfile
---*X-----
返回到您的文件...但不允许向后返回,因为流是单向的(一旦您移动通过文件的一个块,最后一个块将被丢弃)相反,您可以跳过对
getmembers
的调用,一次只访问一个文件:X---*-----
extractfile
读取:---*X----
---*------X
的终点代码上的差别很小,你可以这样做:
只需删除对
get_members
的调用:目前所有的答案都需要下载整个文件,而您可以分块处理它,并根据所处理对象的大小保存大量资源。
除非您不知道存档中的每个文件名就无法执行任何操作,否则没有理由丢弃流响应并等待它被写入磁盘。
6ss1mwsb3#
我在尝试
requests.get
文件时遇到了同样的错误,所以我将所有文件解压缩到了一个tmp目录,而不是使用BytesIO
或extractfile(member)
:c8ib6hqw4#
一个非常简单的解决方案是更改tarfile读取文件的方式,而不是:
变更为:
而重要的部分是在模式中放入":"。
你可以检查this answer以及阅读更多关于它