如何在Python 2.7中将BZ2直接解压缩到Popen stdin?

时间:2015-01-21 19:24:39

标签: python python-2.7 popen bzip2

场景:使用PCAP压缩的BZIP2文件,我想用tcpdump解析并在Python 2.7中逐行列出结果。这就是我的想法:

def tcpdump(filename):
    import subprocess
    import bz2

    p = subprocess.Popen(
        ('tcpdump', '-lnr', '-s', '0', '-'),
        stdin=bz2.BZ2File(filename),
        stdout=subprocess.PIPE)

    try:
        for row in p.stdout:
            yield row.rstrip()
    except KeyboardInterrupt:
        p.terminate()

这个问题是stdin的{​​{1}}参数需要一个实际的文件句柄并抛出此异常:

AttributeError:' bz2.BZ2File'对象没有属性' fileno'

我可以轻松地将其分为两个步骤,但我想避免使用中间临时文件。

想法或建议?

2 个答案:

答案 0 :(得分:2)

使用两个不同的Popen对象:

p1 = subprocess.Popen(['bunzip2', '-c', filename],
    stdout=subprocess.PIPE)
p2 = subprocess.Popen(['tcpdump', '-lnr', '-s', '0', '-'],
    stdin=p1.stdout,
    stdout=subprocess.PIPE)
p1.stdout.close()
for row in iter(p2.stdout.readline, b''):
    ...

答案 1 :(得分:2)

为避免bunzip2依赖,您可以手动输入输入:

import subprocess
import threading
from contextlib import closing

p = subprocess.Popen(['tcpdump', '-lnr', '-s', '0', '-'],
                     stdin=subprocess.PIPE, stdout=subprocess.PIPE, bufsize=-1)
threading.Thread(target=pump, args=[filename, p.stdin]).start()
with closing(p.stdout):
     for line in iter(p.stdout.readline, b''):
         print line,
p.wait()

其中pump()是:

from shutil import copyfileobj

def pump(filename, pipe):
    """Decompress *filename* and write it to *pipe*."""
    with closing(pipe), bz2.BZ2File(filename) as input_file:
         copyfileobj(input_file, pipe)