我正在使用一些相当大的gzip压缩文本文件,我必须解压缩,编辑和重新压缩。我使用Pythons gzip模块进行解压缩和压缩,但我发现我当前的实现远非最佳:
input_file = gzip.open(input_file_name, 'rb')
output_file = gzip.open(output_file_name, 'wb')
for line in input_file:
# Edit line and write to output_file
这种方法难以忍受 - 可能是因为使用gzip模块进行每行迭代涉及巨大的开销:我最初还运行一个行计数例程,其中我 - 使用gzip模块 - 读取文件的块和然后计算每个块中换行符的数量,这非常快!
因此,其中一个优化应该是以块的形式读取我的文件,然后只有在解压缩块后才进行每行迭代。
作为一个额外的优化,我已经看到了一些通过子进程解压缩shell命令的建议。使用这种方法,上面第一行的等价物可以是:
from subprocess import Popen, PIPE
file_input = Popen(["zcat", fastq_filename], stdout=PIPE)
input_file = file_input.stdout
使用此方法,input_file将成为类文件对象。我不确切地知道它在可用属性和方法方面与真实文件对象有何不同,但一个区别是你显然不能使用seek,因为它是一个流而不是一个文件。
这确实运行得更快,它应该 - 除非你在单个核心机器中运行你的脚本声明。后者必须意味着如果可能的话,子进程会自动将不同的线程传送到不同的核心,但我不是那里的专家。
现在问到我目前的问题:我想以类似的方式压缩输出。也就是说,我不想使用Pythons gzip模块,而是将它传递给子进程,然后调用shell gzip。通过这种方式,我可以在单独的核心中进行阅读,编辑和书写,这对我来说听起来非常有效。 我对此做了一个微不足道的尝试,但尝试写入output_file导致一个空文件。最初,我使用touch命令创建一个空文件,因为如果文件不存在,Popen会失败:
call('touch ' + output_file_name, shell=True)
output = Popen(["gzip", output_file_name], stdin=PIPE)
output_file = output.stdin
非常感谢任何帮助,我正在使用Python 2.7。感谢。
答案 0 :(得分:1)
你的意思是output_file = gzip_process.stdin
。之后,您可以使用output_file
,因为您之前使用过gzip.open()
个对象(不寻求)。
如果结果文件为空,请检查您在Python脚本末尾调用output_file.close()
和gzip_process.wait()
。此外,gzip
的使用可能不正确:如果gzip
将压缩输出写入其标准输出,则将stdout=gzip_output_file
传递给gzip_output_file = open(output_file_name, 'wb', 0)
。
答案 1 :(得分:1)
这是一个如何做到这一点的工作示例:
#!/usr/bin/env python
from subprocess import Popen, PIPE
output = ['this', 'is', 'a', 'test']
output_file_name = 'pipe_out_test.txt.gz'
gzip_output_file = open(output_file_name, 'wb', 0)
output_stream = Popen(["gzip"], stdin=PIPE, stdout=gzip_output_file) # If gzip is supported
for line in output:
output_stream.stdin.write(line + '\n')
output_stream.stdin.close()
output_stream.wait()
gzip_output_file.close()
如果我们的脚本只写入控制台并且我们希望输出压缩,那么上面的shell命令可能是:
script_that_writes_to_console | gzip > output.txt.gz