[英]Python equivalent of piping file output to gzip in Perl using a pipe
我需要弄清楚如何在Python中將文件輸出寫入壓縮文件,類似於下面的兩行:
open ZIPPED, "| gzip -c > zipped.gz";
print ZIPPED "Hello world\n";
在 Perl 中,這使用 Unix gzip 將您打印到 ZIPPED 文件句柄的任何內容壓縮到文件“zipped.gz”。
我知道如何使用“import gzip”在 Python 中執行此操作,如下所示:
import gzip
zipped = gzip.open("zipped.gz", 'wb')
zipped.write("Hello world\n")
然而,這是極其緩慢的。 根據分析器,使用該方法占用了我 90% 的運行時間,因為我將 200GB 的未壓縮數據寫入各種輸出文件。 我知道文件系統可能是這里問題的一部分,但我想通過使用 Unix/Linux 壓縮來排除它。 這部分是因為我聽說使用同一個模塊解壓也很慢。
ChristopheD 使用subprocess 模塊的建議是對這個問題的恰當回答。 但是,我不清楚它是否會解決您的性能問題。 您必須測量新代碼的性能才能確定。
要轉換您的示例代碼:
import subprocess
p = subprocess.Popen("gzip -c > zipped.gz", shell=True, stdin=subprocess.PIPE)
p.communicate("Hello World\n")
由於需要向子進程發送大量數據,因此應該考慮使用 Popen 對象的stdin
屬性。 例如:
import subprocess
p = subprocess.Popen("gzip -c > zipped.gz", shell=True, stdin=subprocess.PIPE)
p.stdin.write("Some data")
# Write more data here...
p.communicate() # Finish writing data and wait for subprocess to finish
您可能還會發現此問題中的討論很有幫助。
嘗試這樣的事情:
from subprocess import Popen, PIPE
f = open('zipped.gz', 'w')
pipe = Popen('gzip', stdin=PIPE, stdout=f)
pipe.communicate('Hello world\n')
f.close()
確保在比較速度時使用相同的壓縮級別。 默認情況下,linux gzip 使用級別 6,而 python 使用級別 9。我在 Python 3.6.8 中使用 gzip 版本 1.5 對此進行了測試,壓縮了來自 MySQL 轉儲的 600MB 數據。 使用默認設置:
python 模塊需要 9.24 秒並生成一個 47.1 MB 的文件
subprocess gzip 需要 8.61 秒並生成一個 48.5 MB 的文件
將其更改為第 6 級后,它們匹配:
python 模塊需要 8.09 秒並生成一個 48.6 MB 的文件
subprocess gzip 需要 8.55 秒並生成一個 48.5 MB 的文件
# subprocess method
start = time.time()
with open(outfile, 'wb') as f:
subprocess.run(['gzip'], input=dump, stdout=f, check=True)
print('subprocess finished after {:.2f} seconds'.format(time.time() - start))
# gzip method
start = time.time()
with gzip.open(outfile2, 'wb', compresslevel=6) as z:
z.write(dump)
print('gzip module finished after {:.2f} seconds'.format(time.time() - start))
除了@srgerg
的答案,我想通過禁用 shell 選項shell=False
來應用相同的方法,這也是在@Moishe Lettvin 的答案中完成的,並在( https://stackoverflow.com/a/3172488/2402577 )上推薦。
import subprocess
def zip():
f = open("zipped.gz", "w")
p1 = subprocess.Popen(["echo", "Hello World"], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["gzip", "-9c"], stdin=p1.stdout, stdout=f)
p1.stdout.close()
p2.communicate()
f.close()
請注意,最初我將此p1
s 輸出用於git diff
為:
p1 = subprocess.Popen(["git", "diff"], stdout=subprocess.PIPE)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.