在Python代码中运行“wc -l <文件名>”

11 投票
7 回答
19427 浏览
提问于 2025-04-16 20:31

我想对一些非常大的文件(每个文件有成千上万行)进行10倍交叉验证。每次开始读取文件时,我想先用“wc -l”命令来统计行数,然后生成固定次数的随机数字,每次把那个行号写入一个单独的文件。我现在使用的是:

import os 
for i in files:
    os.system("wc -l <insert filename>").

我该如何在这里插入文件名呢?文件名是一个变量。我看过文档,但大部分都是列出ls命令,这种命令没有这个问题。

7 个回答

4

其实不需要用 wc -l,可以用下面这个 Python 函数。

def file_len(fname):
    with open(fname) as f:
        for i, l in enumerate(f, 1):
            pass
    return i

这个方法可能比调用外部工具要高效,因为它以类似的方式处理输入。

更新

完全错了,wc -l 要快得多!

seq 10000000 > huge_file

$ time wc -l huge_file 
10000000 huge_file

real    0m0.267s
user    0m0.110s
sys 0m0.010s

$ time ./p.py 
10000000

real    0m1.583s
user    0m1.040s
sys 0m0.060s
15

让我们来比较一下:

from subprocess import check_output

def wc(filename):
    return int(check_output(["wc", "-l", filename]).split()[0])

def native(filename):
    c = 0
    with open(filename) as file:
        while True:
            chunk = file.read(10 ** 7)
            if chunk == "":
                return c
            c += chunk.count("\n")

def iterate(filename):
    with open(filename) as file:
        for i, line in enumerate(file):
            pass
        return i + 1

开始使用timeit函数吧!

from timeit import timeit
from sys import argv

filename = argv[1]

def testwc():
    wc(filename)

def testnative():
    native(filename)

def testiterate():
    iterate(filename)

print "wc", timeit(testwc, number=10)
print "native", timeit(testnative, number=10)
print "iterate", timeit(testiterate, number=10)

结果:

wc 1.25185894966
native 2.47028398514
iterate 2.40715694427

所以,在一个大小为150 MB、包含大约500,000个换行符的压缩文件上,wc的速度大约是它的两倍,这是我测试的结果。不过,在一个用seq 3000000 >bigfile生成的文件上,我得到了这些数字:

wc 0.425990104675
native 0.400163888931
iterate 3.10369205475

嘿,看看,python真厉害!不过,当使用更长的行(大约70个字符)时:

wc 1.60881590843
native 3.24313092232
iterate 4.92839002609

所以结论是:这要看情况,但wc似乎是最好的选择。

8
import subprocess
for f in files:
    subprocess.call(['wc', '-l', f])

另外,你可以看看这个链接:http://docs.python.org/library/subprocess.html#convenience-functions。比如说,如果你想把输出结果放到一个字符串里,那么你应该使用 subprocess.check_output(),而不是 subprocess.call()

撰写回答