Python 管道到 `gzip.open` 文件句柄

Python piping to `gzip.open` filehandle

以下代码片段打开一个 gzip 文件句柄并向其写入一行,然后以附加模式再次打开它并将子进程的标准输出重定向到 gzip 文件句柄。

import gzip
import subprocess

with gzip.open("./file.txt.gz", "w") as fh:
    fh.write("this is the first line\n")

with gzip.open("./file.txt.gz", "a") as fh:
    subprocess.call("echo this is the second line", shell=True, stdout=fh)

当我尝试解压缩文件以查看写入的内容时,出现以下错误

$ gunzip file.txt.gz
gzip: file.txt.gz: decompression OK, trailing garbage ignored

解压后的内容只有第一行

$ cat file.txt
this is the first line

当我使用相同的文件句柄来编写一行并作为进程的输出时,我得到一个 gunzip 甚至无法识别的文件。

import gzip
import subprocess

with gzip.open("./file.txt.gz", "w") as fh:
    fh.write("this is the first line\n")
    subprocess.call("echo this is the second line", shell=True, stdout=fh)

例如,生成一个无法 gunzip 的文件。

$ gunzip file.txt.gz

gzip: file.txt.gz: not in gzip format

有没有一种方法可以通过 subprocess 将 gzip 风格的伪文件句柄传递给进程 运行,或者真的没有其他方法可以写入非压缩文件然后返回并返回正在压缩吗?

如果您搜索 Whosebug,您会发现这个问题偶尔会出现,但答案并不总是很容易实现。他们的要点似乎是 subprocess.call() 不能传递伪文件句柄——它必须是真实的。标准的解决方法似乎是使用 subprocess.Popen().

但是,这是我制定的一个简单折衷方案:

import gzip
import subprocess

with gzip.open("file.txt.gz", "wt") as handle:
    handle.write("this is the first line\n")

completed = subprocess.run("echo 'this is the second line'", shell=True, stdout=subprocess.PIPE, universal_newlines=True)

with gzip.open("file.txt.gz", "at") as handle:
    handle.write(completed.stdout)

想法是延迟附加压缩数据,直到子进程完成:

> gzcat file.txt.gz
this is the first line
this is the second line
> 

在 Python 3.5

中添加了 subprocess.run() 功能