我需要在python中获取一个大文件(数十万行)的行数。 内存和时间最有效的方法是什么?

目前,我这样做:

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

有可能做得更好吗?


#1楼

一行,可能非常快:

num_lines = sum(1 for line in open('myfile.txt'))

#2楼

我对该版本进行了小幅改进(4-8%),该版本重新使用了常量缓冲区,因此应避免任何内存或GC开销:

lines = 0
buffer = bytearray(2048)
with open(filename) as f:while f.readinto(buffer) > 0:lines += buffer.count('\n')

您可以尝试使用缓冲区大小,并且可能会看到一些改进。


#3楼

一线如何?

file_length = len(open('myfile.txt','r').read().split('\n'))

使用此方法花费0.003秒在3900线文件上计时

def c():import times = time.time()file_length = len(open('myfile.txt','r').read().split('\n'))print time.time() - s

#4楼

我将使用Python的文件对象方法readlines ,如下所示:

with open(input_file) as foo:lines = len(foo.readlines())

这将打开文件,在文件中创建行列表,计算列表的长度,将其保存到变量中,然后再次关闭文件。


#5楼

print open('file.txt', 'r').read().count("\n") + 1

#6楼

def line_count(path):count = 0with open(path) as lines:for count, l in enumerate(lines, start=1):passreturn count

#7楼

如果要在Linux中的Python中便宜地获得行数,我建议使用以下方法:

import os
print os.popen("wc -l file_path").readline().split()[0]

file_path可以是抽象文件路径,也可以是相对路径。 希望这会有所帮助。


#8楼

凯尔的答案

num_lines = sum(1 for line in open('my_file.txt'))

可能是最好的,对此的替代方法是

num_lines =  len(open('my_file.txt').read().splitlines())

这是两者的性能比较

In [20]: timeit sum(1 for line in open('Charts.ipynb'))
100000 loops, best of 3: 9.79 µs per loopIn [21]: timeit len(open('Charts.ipynb').read().splitlines())
100000 loops, best of 3: 12 µs per loop

#9楼

您可以通过以下方式使用os.path模块:

import os
import subprocess
Number_lines = int( (subprocess.Popen( 'wc -l {0}'.format( Filename ), shell=True, stdout=subprocess.PIPE).stdout).readlines()[0].split()[0] )

,其中FilenameFilename的绝对路径。


#10楼

我不得不将其发布到一个类似的问题上,直到我的声誉得分略有提高(这要感谢任何碰到我的人)。

所有这些解决方案都忽略了一种使运行速度显着提高的方法,即使用无缓冲(原始)接口,使用字节数组以及自己进行缓冲。 (这仅适用于Python3。在Python 2中,默认情况下可能会或可能不会使用raw接口,但是在Python 3中,您将默认使用Unicode。)

使用计时工具的修改版,我相信以下代码比提供的任何解决方案都更快(并且稍微多了一些pythonic):

def rawcount(filename):f = open(filename, 'rb')lines = 0buf_size = 1024 * 1024read_f = f.raw.readbuf = read_f(buf_size)while buf:lines += buf.count(b'\n')buf = read_f(buf_size)return lines

使用单独的生成器函数,可以更快地运行:

def _make_gen(reader):b = reader(1024 * 1024)while b:yield bb = reader(1024*1024)def rawgencount(filename):f = open(filename, 'rb')f_gen = _make_gen(f.raw.read)return sum( buf.count(b'\n') for buf in f_gen )

使用itertools内联生成器表达式可以完全完成此操作,但是看起来很奇怪:

from itertools import (takewhile,repeat)def rawincount(filename):f = open(filename, 'rb')bufgen = takewhile(lambda x: x, (f.raw.read(1024*1024) for _ in repeat(None)))return sum( buf.count(b'\n') for buf in bufgen )

这是我的时间安排:

function      average, s  min, s   ratio
rawincount        0.0043  0.0041   1.00
rawgencount       0.0044  0.0042   1.01
rawcount          0.0048  0.0045   1.09
bufcount          0.008   0.0068   1.64
wccount           0.01    0.0097   2.35
itercount         0.014   0.014    3.41
opcount           0.02    0.02     4.83
kylecount         0.021   0.021    5.05
simplecount       0.022   0.022    5.25
mapcount          0.037   0.031    7.46

#11楼

为了完成上述方法,我尝试了使用fileinput模块的变体:

import fileinput as fi
def filecount(fname):for line in fi.input(fname):passreturn fi.lineno()

并向上述所有方法传递了6000万行文件:

mapcount : 6.1331050396
simplecount : 4.588793993
opcount : 4.42918205261
filecount : 43.2780818939
bufcount : 0.170812129974

令我感到惊讶的是,fileinput的性能和扩展性都比其他方法差很多。


#12楼

另一种可能性:

import subprocessdef num_lines_in_file(fpath):return int(subprocess.check_output('wc -l %s' % fpath, shell=True).strip().split()[0])

#13楼

该代码更短,更清晰。 这可能是最好的方法:

num_lines = open('yourfile.ext').read().count('\n')

#14楼

这是我发现使用纯python最快的东西。 您可以通过设置缓冲区使用任意数量的内存,尽管2 ** 16似乎是我计算机上的最佳选择。

from functools import partialbuffer=2**16
with open(myfile) as f:print sum(x.count('\n') for x in iter(partial(f.read,buffer), ''))

我在这里找到了答案, 为什么在C ++中从stdin读取行比在Python中慢? 并稍作调整。 尽管wc -l仍然比其他任何方法快约75%,但它还是理解如何快速计数行的很好阅读。


#15楼

一线解决方案:

import os
os.system("wc -l  filename")

我的片段:

>>> os.system('wc -l *.txt')0 bar.txt
1000 command.txt
3 test_file.txt
1003 total

#16楼

使用现代subprocess.check_output函数,类似于此答案的单行bash解决方案:

def line_count(file):return int(subprocess.check_output('wc -l {}'.format(file), shell=True).split()[0])

#17楼

这是我用的,看起来很干净:

import subprocessdef count_file_lines(file_path):"""Counts the number of lines in a file using wc utility.:param file_path: path to file:return: int, no of lines"""num = subprocess.check_output(['wc', '-l', file_path])num = num.split(' ')return int(num[0])

更新:这比使用纯python快一点,但是以内存使用为代价。 子进程将在执行命令时派生一个与父进程具有相同内存占用量的新进程。


#18楼

def count_text_file_lines(path):with open(path, 'rt') as file:line_count = sum(1 for _line in file)return line_count

#19楼

简单方法:

1)

>>> f = len(open("myfile.txt").readlines())
>>> f430

2)

>>> f = open("myfile.txt").read().count('\n')
>>> f
430
>>>

3)

num_lines = len(list(open('myfile.txt')))

#20楼

count = max(enumerate(open(filename)))[0]


#21楼

这个怎么样?

import fileinput
import syscounter=0
for line in fileinput.input([sys.argv[1]]):counter+=1fileinput.close()
print counter

#22楼

这是一个使用多处理库在机器/内核之间分配行数的python程序。 我的测试使用8核Windows 64服务器将2000万行文件的计数从26秒提高到7秒。 注意:不使用内存映射会使事情变慢。

import multiprocessing, sys, time, os, mmap
import logging, logging.handlersdef init_logger(pid):console_format = 'P{0} %(levelname)s %(message)s'.format(pid)logger = logging.getLogger()  # New logger at root levellogger.setLevel( logging.INFO )logger.handlers.append( logging.StreamHandler() )logger.handlers[0].setFormatter( logging.Formatter( console_format, '%d/%m/%y %H:%M:%S' ) )def getFileLineCount( queues, pid, processes, file1 ):init_logger(pid)logging.info( 'start' )physical_file = open(file1, "r")#  mmap.mmap(fileno, length[, tagname[, access[, offset]]]m1 = mmap.mmap( physical_file.fileno(), 0, access=mmap.ACCESS_READ )#work out file size to divide up line countingfSize = os.stat(file1).st_sizechunk = (fSize / processes) + 1lines = 0#get where I start and stop_seedStart = chunk * (pid)_seekEnd = chunk * (pid+1)seekStart = int(_seedStart)seekEnd = int(_seekEnd)if seekEnd < int(_seekEnd + 1):seekEnd += 1if _seedStart < int(seekStart + 1):seekStart += 1if seekEnd > fSize:seekEnd = fSize#find where to startif pid > 0:m1.seek( seekStart )#read next linel1 = m1.readline()  # need to use readline with memory mapped filesseekStart = m1.tell()#tell previous rank my seek start to make their seek endif pid > 0:queues[pid-1].put( seekStart )if pid < processes-1:seekEnd = queues[pid].get()m1.seek( seekStart )l1 = m1.readline()while len(l1) > 0:lines += 1l1 = m1.readline()if m1.tell() > seekEnd or len(l1) == 0:breaklogging.info( 'done' )# add up the resultsif pid == 0:for p in range(1,processes):lines += queues[0].get()queues[0].put(lines) # the total lines countedelse:queues[0].put(lines)m1.close()physical_file.close()if __name__ == '__main__':init_logger( 'main' )if len(sys.argv) > 1:file_name = sys.argv[1]else:logging.fatal( 'parameters required: file-name [processes]' )exit()t = time.time()processes = multiprocessing.cpu_count()if len(sys.argv) > 2:processes = int(sys.argv[2])queues=[] # a queue for each processfor pid in range(processes):queues.append( multiprocessing.Queue() )jobs=[]prev_pipe = 0for pid in range(processes):p = multiprocessing.Process( target = getFileLineCount, args=(queues, pid, processes, file_name,) )p.start()jobs.append(p)jobs[0].join() #wait for counting to finishlines = queues[0].get()logging.info( 'finished {} Lines:{}'.format( time.time() - t, lines ) )

#23楼

我修改了这样的缓冲情况:

def CountLines(filename):f = open(filename)try:lines = 1buf_size = 1024 * 1024read_f = f.read # loop optimizationbuf = read_f(buf_size)# Empty fileif not buf:return 0while buf:lines += buf.count('\n')buf = read_f(buf_size)return linesfinally:f.close()

现在,空文件和最后一行(不带\\ n)也被计算在内。


#24楼

您可以执行一个子进程并运行wc -l filename

import subprocessdef file_len(fname):p = subprocess.Popen(['wc', '-l', fname], stdout=subprocess.PIPE, stderr=subprocess.PIPE)result, err = p.communicate()if p.returncode != 0:raise IOError(err)return int(result.strip().split()[0])

#25楼

def file_len(full_path):""" Count number of lines in a file."""f = open(full_path)nr_of_lines = sum(1 for line in f)f.close()return nr_of_lines

#26楼

没有比这更好的了。

毕竟,任何解决方案都必须读取整个文件,找出有多少\\n ,然后返回结果。

您是否有一种更好的方法,而无需读取整个文件? 不确定...最好的解决方案将永远是受I / O约束的,您可以做的最好的事情就是确保您不使用不必要的内存,但是看起来您已经解决了这一问题。


#27楼

对于我来说,这种变体将是最快的:

#!/usr/bin/env pythondef main():f = open('filename')                  lines = 0buf_size = 1024 * 1024read_f = f.read # loop optimizationbuf = read_f(buf_size)while buf:lines += buf.count('\n')buf = read_f(buf_size)print linesif __name__ == '__main__':main()

原因:缓冲速度比逐行和string.count读取还快


#28楼

打开文件的结果是一个迭代器,可以将其转换为长度为以下的序列:

with open(filename) as f:return len(list(f))

这比您的显式循环更为简洁,并且避免了enumerate


#29楼

那这个呢

def file_len(fname):counts = itertools.count()with open(fname) as f: for _ in f: counts.next()return counts.next()

#30楼

我相信内存映射文件将是最快的解决方案。 我尝试了四个函数:OP( opcount )发布的函数; 在文件中的行上进行简单迭代( simplecount ); 带有内存映射mapcount (mmap)的readline( mapcount ); 以及Mykola Kharechko( bufcount )提供的缓冲区读取解决方案。

我对每个函数运行了五次,并计算了120万行文本文件的平均运行时间。

Windows XP,Python 2.5、2GB RAM,2 GHz AMD处理器

这是我的结果:

mapcount : 0.465599966049
simplecount : 0.756399965286
bufcount : 0.546800041199
opcount : 0.718600034714

编辑 :Python 2.6的数字:

mapcount : 0.471799945831
simplecount : 0.634400033951
bufcount : 0.468800067902
opcount : 0.602999973297

因此,缓冲区读取策略似乎对于Windows / Python 2.6是最快的

这是代码:

from __future__ import with_statement
import time
import mmap
import random
from collections import defaultdictdef mapcount(filename):f = open(filename, "r+")buf = mmap.mmap(f.fileno(), 0)lines = 0readline = buf.readlinewhile readline():lines += 1return linesdef simplecount(filename):lines = 0for line in open(filename):lines += 1return linesdef bufcount(filename):f = open(filename)                  lines = 0buf_size = 1024 * 1024read_f = f.read # loop optimizationbuf = read_f(buf_size)while buf:lines += buf.count('\n')buf = read_f(buf_size)return linesdef opcount(fname):with open(fname) as f:for i, l in enumerate(f):passreturn i + 1counts = defaultdict(list)for i in range(5):for func in [mapcount, simplecount, bufcount, opcount]:start_time = time.time()assert func("big_file.txt") == 1209138counts[func].append(time.time() - start_time)for key, vals in counts.items():print key.__name__, ":", sum(vals) / float(len(vals))

如何在Python中便宜地获取大文件的行数?相关推荐

  1. java高效获取大文件的行数

    方式1 : 利用LineNumberReader public static int getFileLineNum(String filePath) {try (LineNumberReader li ...

  2. 如何用python最快的获取大文件的最后几行

    工作中经常会遇到处理日志文件的问题:为了得到日志的最新状态,我们需要获取日志文件的最后部分行来做判断.那么,这种情况下我们应该怎么做呢? 1)常规方法:从前往后依次读取 步骤:open打开日志文件. ...

  3. 如何在Python中优雅地处理JSON文件

    1. 引言 在本文中,我们将学习如何使用Python读取.解析和编写JSON文件. 我们将讨论如何最好地处理简单的JSON文件以及嵌套的JSON文件,当然我们也将讨论如何访问Json文件数据中的特定值 ...

  4. python中zipfile的使用_如何在Python中使用ZIPFILE模块压缩文件。

    问题 您要在python中创建一个压缩文件. 介绍 ZIP文件可以保存许多其他文件的压缩内容.压缩文件会减小其在磁盘上的大小,这在通过Internet或使用Control-m AFT或Connect ...

  5. python语言结构化语言_如何在python中处理结构化语言文件

    我有一个像这样的大型结构化语言文件:TASK SchM_Task { TYPE = AUTO; SCHEDULE = NON; PRIORITY = 160; ACTIVATION = 1; TIMI ...

  6. python编写html文件,如何在python中编写和保存html文件?

    ' % (colour[j % len(colour)], k))等有什么问题? 另外,你混合了print"string"和print("string").坚持 ...

  7. python查看文件行数_python如何获取打开文件的行数?

    距离上次写爬虫文章已经过了许久了,之前写过一篇20行Python代码爬取王者荣耀全英雄皮肤 ,反响强烈,其中有很多同学希望我再写一篇针对英雄联盟官网的皮肤爬取,但苦于事情繁多,便 2020-11-28 ...

  8. linux使用grep条件搜索大文件的行数等操作

    一.前言 最近需要查询大日志文件的时候,每次打开vim,cat之类的都会卡死,但是需要查看符合条件的共有多少行数据,这颗愁死我了,下面列出一些常用的匹配查询命令. 二.常用的搜索命令 1.grep搜索 ...

  9. 【Python】如何在python中执行另一个py文件

    使用命令:os.system('python file_name.py') 解释:os.system是执行当前的系统命令 1.拿windows系统举例: # 由于ipconfig/all在window ...

最新文章

  1. 客户端动态调用WCF服务中的方法
  2. C什么k什么_cssci跟c刊有什么区别
  3. Spring4 学习系列之——jdbc事务的基本实现和了解
  4. android addview指定位置,Android开发中,请问当在一个视图中addView另一个布局视图时为什么报错?...
  5. 原生JS实现addClass,removeClass,toggleClass
  6. 8年了,开始写点东西了
  7. Git学习总结(12)——多人开发 Git 分支管理详解
  8. python画简便的图-python如何画出漂亮的地图?网友:教教我呗
  9. 1、检测是用那个浏览器打开的
  10. 软件资源消耗测试,综合测试:性能与资源消耗堪称完美
  11. 【超图+CESIUM】【基础API使用示例】09、超图|CESIUM - 场景分屏设置
  12. 链表-快慢指针(C++)
  13. 悲剧的山寨采用的新芯片资料汇总(更新Rk3066)
  14. 如何将自己写的项目发布到外网上
  15. WikiExtractor.py(维基百科抽取器)
  16. js正则表达式判断非负数和是否为网址
  17. Unity TileMap工具教程
  18. 集装箱编号校验码规则及java/JavaScript的实现
  19. 关于CSS选择器的权重计算
  20. windows远程桌面占用CPU的处理办法

热门文章

  1. form中的get和post方法
  2. linux 静态路由修改
  3. JavaScript(3)——Object-Oriented Design
  4. Django 项目一补充
  5. C++设计模式——观察者模式(转)
  6. iOS基础 - UIDynamic
  7. 升级Linux下的sudo
  8. Linux篇:通配符的应用
  9. 为什么访问不了外网,使用ping命令却能得到网站对应的IP地址
  10. eclipse IDE侵入式与非侵入式安装插件方法