[英]How do I pipe to a file or shell program via Pythons subprocess?
我正在處理一些相當大的壓縮文本文件,這些文件必須解壓縮,編輯和重新壓縮。 我使用Python的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成為一個類似文件的對象。 我不知道就可用屬性和方法而言,它與真實文件對象有何不同,但一個區別是,顯然它不能使用搜索,因為它是流而不是文件。
這確實運行得更快,並且應該-除非您在單台核心計算機上運行腳本,否則聲明是這樣。 后者必須表示,如果可能的話,子進程會自動將不同的線程運送到不同的內核,但是我不是專家。
現在是我當前的問題:我想以類似的方式壓縮輸出。 也就是說,我不想使用Python的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。 謝謝。
您的意思是output_file = gzip_process.stdin
。 之后,您可以像以前使用gzip.open()
對象一樣使用output_file
(不查找)。
如果結果文件為空,請檢查是否在Python腳本末尾調用了output_file.close()
和gzip_process.wait()
。 同樣, gzip
的用法可能不正確:如果gzip
將壓縮的輸出寫入其stdout,則傳遞stdout=gzip_output_file
,其中gzip_output_file = open(output_file_name, 'wb', 0)
。
這是一個如何完成此工作的示例:
#!/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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.