2

私はpythonが初めてです。tarfile の内容を Python に読み込むのに問題があります。

データはジャーナル記事の内容です (pubmed central でホストされています)。以下の情報を参照してください。そして、Pythonに読み込みたいtarfileへのリンク。

http://www.pubmedcentral.nih.gov/utils/oa/oa.fcgi?id=PMC13901 ftp://ftp.ncbi.nlm.nih.gov/pub/pmc/b0/ac/Breast_Cancer_Res_2001_Nov_9_3(1)_61 -65.tar.gz

同様の .tar.gz ファイルのリストがあり、最終的には同様に読み込みたいと考えています。すべての tarfile に .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の回答へのリンク):

Web サイトから .tar.gz ファイルの内容を python 3.x オブジェクトに読み込みます

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

3 に答える 3

13

問題の原因: tar ファイルはインターリーブされて保存されます。それらは、ヘッダー、データ、ヘッダー、データ、ヘッダー、データなどの順序で表示されます。 でファイルを列挙したときgetmembers()、ヘッダーを取得するためにファイル全体を既に読んでいます。次に、tarfile オブジェクトにデータの読み取りを要求すると、最後のヘッダーから最初のデータまで逆方向にシークしようとしました。ただし、urllib 要求を閉じてから再度開かないと、ネットワーク ストリームを逆方向にシークすることはできません。

回避方法:ファイルをダウンロードし、一時コピーをディスクまたは StringIO に保存し、この一時コピー内のファイルを列挙してから、必要なファイルを抽出する必要があります。

#!/usr/bin/env python3
from io import BytesIO
import urllib.request
import tarfile

tarfile_url = "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_url)

# BytesIO creates an in-memory temporary file.
# See the Python manual: http://docs.python.org/3/library/io.html
tmpfile = BytesIO()
while True:
    # Download a piece of the file from the connection
    s = ftpstream.read(16384)

    # Once the entire file has been downloaded, tarfile returns b''
    # (the empty bytes) which is a falsey value
    if not s:  
        break

    # Otherwise, write the piece of the file to the temporary file.
    tmpfile.write(s)
ftpstream.close()

# Now that the FTP stream has been downloaded to the temporary file,
# we can ditch the FTP stream and have the tarfile module work with
# the temporary file.  Begin by seeking back to the beginning of the
# temporary file.
tmpfile.seek(0)

# Now tell the tarfile module that you're using a file object
# that supports seeking backward.
# r|gz forbids seeking backward; r:gz allows seeking backward
tfile = tarfile.open(fileobj=tmpfile, mode="r:gz")

# You want to limit it to the .nxml files
tfile_members2 = [filename
                  for filename in tfile.getnames()
                  if filename.endswith('.nxml')]

tfile_extract1 = tfile.extractfile(tfile_members2[0])
tfile_extract1_text = tfile_extract1.read()

# And when you're done extracting members:
tfile.close()
tmpfile.close()
于 2013-09-04T21:41:17.937 に答える