def file_len(filename):
with open(filename) as f:
for i, _ in enumerate(f):
pass
return i + 1
def file_len(filename):
with open(filename) as f:
for i, _ in enumerate(f):
pass
return i + 1
>>> f = len(open("myfile.txt").readlines())
>>> f
430
>>> f = open("myfile.txt").read().count('\n')
>>> f
430
>>>
num_lines = len(list(open('myfile.txt')))
import os
print os.popen("wc -l file_path").readline().split()[0]
file_path 可以是抽象的文件路径或相对路径。希望这能有所帮助。
print open('file.txt', 'r').read().count("\n") + 1
行读取和缓冲的 \n
计数技术不会对每个文件返回相同的答案,因为某些文本文件在最后一行没有换行符。你可以通过检查最后一个非空缓冲区的最后一个字节并在其不是 b'\n'
时添加 1 来解决这个问题。
在 Python 3 中,以文本模式和二进制模式打开文件可能会产生不同的结果,因为文本模式默认将 CR、LF 和 CRLF 识别为行尾(将它们全部转换为 '\n'
),而在二进制模式下只有 LF 和 CRLF 会被计算为 b'\n'
。无论你是按行读取还是读入固定大小的缓冲区,都是如此。经典的 Mac OS 使用 CR 作为行尾;我不知道这些文件现在有多常见。
缓冲区读取方法使用的 RAM 量是有限的,与文件大小无关,而行读取方法在最坏情况下可能会一次性将整个文件读入 RAM 中(特别是如果文件使用 CR 行尾)。在最坏情况下,它可能会使用比文件大小更多得多的 RAM,因为动态调整行缓冲区大小和(如果你以文本模式打开)Unicode 解码和存储都会带来开销。
你可以通过预先分配 bytearray 并使用 readinto
而不是 read
来改善缓冲区方法的内存使用情况,而且可能还能提高速度。其中一个现有答案(票数较少)就是这样做的,但它有 bug(它会重复计算一些字节)。
顶部的缓冲区读取答案使用了一个大缓冲区(1 MiB)。使用更小的缓冲区实际上可能更快,因为操作系统会进行预读取。如果每次读取 32K 或 64K,操作系统可能会在你请求数据之前开始将下一个 32K/64K 读入缓存中,并且每次访问内核都几乎立即返回。如果每次读取 1 MiB,操作系统不太可能预读整个兆字节。它可能会预读更少的数据,但你仍然需要花费相当长的时间在内核中等待磁盘返回其余的数据。
我们可以使用Numba将函数即时编译为机器码。 def numbacountparallel(fname)
运行速度比问题中的def file_len(fname)
快2.8倍。
在基准测试运行之前,操作系统已经将文件缓存到内存中,因此我在我的PC上看不到太多的磁盘活动。当第一次读取文件时,时间会慢得多,使得使用Numba的时间优势微不足道。
JIT编译在第一次调用函数时需要额外的时间。
如果我们要做的不仅仅是计算行数,这将非常有用。
Cython是另一个选择。
由于计算行数将受到IO限制,因此除非您想要执行更多操作而不仅仅是计算行数,否则请使用问题中的def file_len(fname)函数。
import timeit
from numba import jit, prange
import numpy as np
from itertools import (takewhile,repeat)
FILE = '../data/us_confirmed.csv' # 40.6MB, 371755 line file
CR = ord('\n')
# Copied from the question above. Used as a benchmark
def file_len(fname):
with open(fname) as f:
for i, l in enumerate(f):
pass
return i + 1
# Copied from another answer. Used as a benchmark
def rawincount(filename):
f = open(filename, 'rb')
bufgen = takewhile(lambda x: x, (f.read(1024*1024*10) for _ in repeat(None)))
return sum( buf.count(b'\n') for buf in bufgen )
# Single thread
@jit(nopython=True)
def numbacountsingle_chunk(bs):
c = 0
for i in range(len(bs)):
if bs[i] == CR:
c += 1
return c
def numbacountsingle(filename):
f = open(filename, "rb")
total = 0
while True:
chunk = f.read(1024*1024*10)
lines = numbacountsingle_chunk(chunk)
total += lines
if not chunk:
break
return total
# Multi thread
@jit(nopython=True, parallel=True)
def numbacountparallel_chunk(bs):
c = 0
for i in prange(len(bs)):
if bs[i] == CR:
c += 1
return c
def numbacountparallel(filename):
f = open(filename, "rb")
total = 0
while True:
chunk = f.read(1024*1024*10)
lines = numbacountparallel_chunk(np.frombuffer(chunk, dtype=np.uint8))
total += lines
if not chunk:
break
return total
print('numbacountparallel')
print(numbacountparallel(FILE)) # This allows Numba to compile and cache the function without adding to the time.
print(timeit.Timer(lambda: numbacountparallel(FILE)).timeit(number=100))
print('\nnumbacountsingle')
print(numbacountsingle(FILE))
print(timeit.Timer(lambda: numbacountsingle(FILE)).timeit(number=100))
print('\nfile_len')
print(file_len(FILE))
print(timeit.Timer(lambda: rawincount(FILE)).timeit(number=100))
print('\nrawincount')
print(rawincount(FILE))
print(timeit.Timer(lambda: rawincount(FILE)).timeit(number=100))
每个函数100次调用所需的秒数
numbacountparallel
371755
2.8007332000000003
numbacountsingle
371755
3.1508585999999994
file_len
371755
6.7945494
rawincount
371755
6.815438
def count_text_file_lines(path):
with open(path, 'rt') as file:
line_count = sum(1 for _line in file)
return line_count
with open(filename) as f:
return len(list(f))
这种方法比你的显式循环更简洁,而且避免了使用enumerate
。
这个怎么样?
import fileinput
import sys
counter=0
for line in fileinput.input([sys.argv[1]]):
counter+=1
fileinput.close()
print counter
file_length = len(open('myfile.txt','r').read().split('\n'))
def c():
import time
s = time.time()
file_length = len(open('myfile.txt','r').read().split('\n'))
print time.time() - s
对于大文件的替代方案是使用xreadlines():
。
count = 0
for line in open(thefilepath).xreadlines( ): count += 1
对于Python 3,请参见:Python 3中的替代xreadlines()是什么?
enumerate(f, 1)
代替range(len(f))
并省略i + 1
? - Ian Mackinnon