在Python中下载、解压并读取gzip文件
我想在Python中下载、解压和遍历一个文本文件,而不想创建临时文件。
基本上,就是想在Python中实现这个管道功能。
curl ftp://ftp.theseed.org/genomes/SEED/SEED.fasta.gz | gunzip | processing step
这是我的代码:
def main():
import urllib
import gzip
# Download SEED database
print 'Downloading SEED Database'
handle = urllib.urlopen('ftp://ftp.theseed.org/genomes/SEED/SEED.fasta.gz')
with open('SEED.fasta.gz', 'wb') as out:
while True:
data = handle.read(1024)
if len(data) == 0: break
out.write(data)
# Extract SEED database
handle = gzip.open('SEED.fasta.gz')
with open('SEED.fasta', 'w') as out:
for line in handle:
out.write(line)
# Filter SEED database
pass
我不想使用process.Popen()或者其他什么方法,因为我希望这个脚本能在不同的平台上都能运行。
问题是Gzip库只接受文件名作为参数,而不接受文件句柄。使用“管道”的原因是下载步骤只占用大约5%的CPU,这样同时进行解压和处理会更快。
补充说明:
“由于gzip压缩的工作原理,GzipFile需要保存它的位置,并在压缩文件中前后移动。当“文件”是来自远程服务器的字节流时,这种方式就不行了;你只能一次获取一个字节,而不能在数据流中前后移动。” - 深入Python
这就是我为什么会遇到错误的原因。
AttributeError: addinfourl instance has no attribute 'tell'
那么,curl url | gunzip | whatever
是怎么工作的呢?
4 个回答
2
我在寻找从网址下载并解压一个 gzip
文件的方法时,发现了这个问题,但我没能让被接受的答案在 Python 2.7 中运行。
以下是我找到的有效方法(改编自 这里):
import urllib2
import gzip
import StringIO
def download(url):
# Download SEED database
out_file_path = url.split("/")[-1][:-3]
print('Downloading SEED Database from: {}'.format(url))
response = urllib2.urlopen(url)
compressed_file = StringIO.StringIO(response.read())
decompressed_file = gzip.GzipFile(fileobj=compressed_file)
# Extract SEED database
with open(out_file_path, 'w') as outfile:
outfile.write(decompressed_file.read())
# Filter SEED database
# ...
return
if __name__ == "__main__":
download("ftp://ftp.ebi.ac.uk/pub/databases/Rfam/12.0/fasta_files/RF00001.fa.gz")
我更改了目标网址,因为原来的链接已经失效:我只是找了一个从 FTP 服务器上提供的 gzip
文件,就像原问题中提到的那样。
3
这是一个用 python3
写的解决方案,它不需要使用 for
循环,并且直接将 byte
对象作为 binary
流写入:
import gzip
import urllib.request
def download_file(url):
out_file = '/path/to/file'
# Download archive
try:
# Read the file inside the .gz archive located at url
with urllib.request.urlopen(url) as response:
with gzip.GzipFile(fileobj=response) as uncompressed:
file_content = uncompressed.read()
# write to file in binary mode 'wb'
with open(out_file, 'wb') as f:
f.write(file_content)
return 0
except Exception as e:
print(e)
return 1
你可以用 retval=download_file(url)
来调用这个函数,以获取 返回值
9
只需要用 gzip.GzipFile(fileobj=handle)
这个方法就可以了。换句话说,"Gzip库只接受文件名作为参数,而不接受文件句柄" 这个说法并不完全正确。你只需要使用 fileobj=
这个命名参数就可以了。