【问题标题】:using gzip file as stdin for commands executed using subprocess.call使用 gzip 文件作为使用 subprocess.call 执行的命令的标准输入
【发布时间】:2017-04-29 20:49:45
【问题描述】:

我有一个 python 脚本,使用subprocess.call() 执行多个命令。我需要使用标准输入将 gzip 压缩文件中的数据传递给其中一个命令,但无论我做什么,该命令显然都会获取 gzip 压缩数据。

这是我认为应该起作用的:

import gzip
from subprocess import call

in_fname = 'test.gz'
out_fname = 'test.txt'

gz = gzip.open(in_fname, 'rb')
txt = open(out_fname, 'w')

call(['cat'], stdin=gz, stdout=txt)

但最后,'test.txt' 被压缩并且与压缩后的输入文件大小完全相同。

如果我调用gz.read(),那么我会得到正确的解压缩数据,正如预期的那样。要将 gzip 压缩文件用作标准输入,我需要做什么?

【问题讨论】:

    标签: python gzip


    【解决方案1】:

    经过一番研究,问题的根源在于您的操作系统不知道 gzip 压缩文件的文件句柄有什么特别之处。基本上,gzip 提供了一个“类文件”接口,但子进程(在这种情况下为cat)不知道这是一个需要解压缩的特殊文件。因此,它只是逐字节读取文件并打印出它读取的乱码。

    我的下一个想法是在 python 中读取整个文件(它知道它已被压缩并将解压缩),然后将字符串传递给子进程。我搞砸了将解压缩的内容包装在 StringIO 对象中,但事实证明这不起作用。另一个答案 (Use StringIO as stdin with Popen) 提到对subprocess 的调用略有不同:

    import gzip
    from subprocess import Popen, PIPE
    
    in_fname = 'test.gz'
    out_fname = 'test.txt'
    
    with gzip.open(in_fname, 'rb') as f:
      gz = f.read()
    txt = open(out_fname, 'w')
    
    
    process = Popen(['cat'], stdin=PIPE, stdout=txt)
    process.communicate(gz)
    

    哪个有效。请注意,这需要将整个文件读入内存,这对于非常大的文件可能是个问题。

    【讨论】:

    • 是的,特别但不特别 :-/gzip 提供了返回压缩数据的类似文件的对象,这有点奇怪/意外 - 我想知道它的用例是什么。无论如何,最后我决定在一个 Popen 中简单地调用 gunzip,在另一个 Popen 中调用另一个命令,然后我从第一个的标准输出中读取()并将其写入()到另一个。将整个文件读入内存对我来说不是一个选择,因为文件可能非常大。此外,这种方式的解压方式比 Python 中的解压方式要快得多。
    猜你喜欢
    • 2011-12-04
    • 2015-06-19
    • 1970-01-01
    • 2016-04-19
    • 2015-04-16
    • 2010-09-13
    • 1970-01-01
    • 2013-02-16
    • 1970-01-01
    相关资源
    最近更新 更多