在一步中以Pythonic方式将文件内容发送到管道并计算行数
给定一个超过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 -- 请在调用时替换成正确的参数。