在一步中以Pythonic方式将文件内容发送到管道并计算行数

4 投票
4 回答
1904 浏览
提问于 2025-04-17 08:26

给定一个超过4GB的文件myfile.gz,我需要把它通过zcat命令放入一个管道中,以便Teradata的fastload可以使用。同时,我还需要统计文件中的行数。理想情况下,我只想对文件进行一次读取。我使用awk命令将整行内容($0)输出到标准输出,并通过awk的END部分,将行数(awk的NR变量)写入另一个文件描述符(outfile)。

我已经用awk成功实现了这个功能,但我想知道有没有更符合Python风格的方法。

#!/usr/bin/env python
from subprocess import Popen, PIPE
from os import path

the_file = "/path/to/file/myfile.gz"

outfile = "/tmp/%s.count" % path.basename(the_file)
cmd = ["-c",'zcat %s | awk \'{print $0} END {print NR > "%s"} \' ' % (the_file, outfile)]
zcat_proc = Popen(cmd, stdout = PIPE, shell=True)

这个管道稍后会被Teradata的fastload调用,它会从

"/dev/fd/" + str(zcat_proc.stdout.fileno())

读取数据。这个方法有效,但我想知道是否可以跳过awk,更好地利用Python。我也愿意尝试其他方法。我有多个大文件需要以这种方式处理。

4 个回答

1

这可以用一行简单的bash命令来完成:

zcat myfile.gz | tee >(wc -l >&2) | fastload

这个命令会把行数打印到错误输出(stderr)上。如果你想把结果放到别的地方,可以根据需要调整输出的方向。

7

其实不需要用到zcat或者Awk。要计算一个压缩文件里的行数,可以直接用下面的命令:

import gzip

nlines = sum(1 for ln in gzip.open("/path/to/file/myfile.gz"))

如果你想对这些行做其他操作,比如把它们传给另一个程序,可以使用:

nlines = 0
for ln in gzip.open("/path/to/file/myfile.gz"):
    nlines += 1
    # pass the line to the other process
3

用Python和它自带的库,可以很简单地统计行数和解压缩gzip格式的文件。而且你可以一次性完成所有操作:

import gzip, subprocess, os
fifo_path = "path/to/fastload-fifo"
os.mkfifo(fifo_path)
fastload_fifo = open(fifo_path)
fastload = subprocess.Popen(["fastload", "--read-from", fifo_path],
                            stdin=subprocess.PIPE)
with gzip.open("/path/to/file/myfile.gz") as f:
    for i, line in enumerate(f):
         fastload_fifo.write(line)
    print "Number of lines", i + 1
os.unlink(fifo_path)

我不知道怎么调用Fastload -- 请在调用时替换成正确的参数。

撰写回答