Como obter a contagem de linhas de um arquivo grande mais barato em Python?

1012

Eu preciso obter uma contagem de linhas de um arquivo grande (centenas de milhares de linhas) em python. Qual é a maneira mais eficiente em termos de memória e tempo?

No momento eu faço:

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

é possível fazer melhor?

SilentGhost
fonte
7
Você precisa da contagem exata de linhas ou será suficiente uma aproximação?
11/05/09
43
Eu adicionaria i = -1 antes do loop for, pois esse código não funciona para arquivos vazios.
Maciek Sawicki
12
@ Legend: Aposto que o pico está pensando, obtenha o tamanho do arquivo (com busca (0,2) ou equivalente), divida pelo comprimento aproximado da linha. Você pode ler algumas linhas no início para adivinhar o comprimento médio da linha.
217 Anne
32
enumerate(f, 1)e abandonar o i + 1?
Ian Mackinnon
4
@IanMackinnon Funciona para arquivos vazios, mas você precisa inicializar i para 0 antes do loop for.
Scal

Respostas:

357

Você não pode ficar melhor do que isso.

Afinal, qualquer solução precisará ler o arquivo inteiro, descobrir quantas \nvocê possui e retornar esse resultado.

Você tem uma maneira melhor de fazer isso sem ler o arquivo inteiro? Não tenho certeza ... A melhor solução será sempre ligada à E / S, o melhor que você pode fazer é garantir que você não use memória desnecessária, mas parece que você a cobriu.

Yuval Adam
fonte
7
Exatamente, até o WC está lendo o arquivo, mas em C e provavelmente é bastante otimizado.
Ólafur Waage
6
Tanto quanto eu entendo, o arquivo Python IO é feito através de C também. docs.python.org/library/stdtypes.html#file-objects
Tomalak
9
@Tomalak Isso é um arenque vermelho. Embora python e wc possam estar emitindo os mesmos syscalls, o python possui uma sobrecarga de despacho de código de código que wc não possui.
bobpoekert
4
Você pode aproximar uma contagem de linhas por amostragem. Pode ser milhares de vezes mais rápido. Veja: documentroot.com/2011/02/…
Erik Aronesty
4
Outras respostas parecem indicar que esta resposta categórica está errada e, portanto, deve ser excluída em vez de ser mantida como aceita.
Skippy le Grand Gourou
625

Uma linha, provavelmente bem rápida:

num_lines = sum(1 for line in open('myfile.txt'))
Kyle
fonte
8
é semelhante à soma (sequência de 1) todas as linhas contam como 1. >>> [1 para a linha no intervalo (10)] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] >>> soma (1 para a linha no intervalo (10)) 10 >>>
James Sapam
4
num_lines = sum (1 para a linha em aberto ('myfile.txt') se line.rstrip ()) para filtrar linhas vazias
Honghe.Wu 03/03
61
quando abrirmos um arquivo, ele será fechado automaticamente quando iterarmos sobre todos os elementos? É necessário 'close ()'? Acho que não podemos usar 'com open ()' nesta declaração curta, certo?
Mannaggia
16
@Annaggia você está correto, seria melhor usar 'with open (filename)' para garantir que o arquivo seja fechado quando terminar, e ainda melhor é fazer isso dentro de um bloco try-except, onde a exceção IOError será lançada se o arquivo não pode ser aberto.
BoltzmannBrain
17
Outra coisa a ser observada: é ~ 0,04-0,05 segundos mais lento que o problema original em um arquivo de texto de 300 mil linhas
andrew
202

Acredito que um arquivo mapeado de memória será a solução mais rápida. Eu tentei quatro funções: a função postada pelo OP ( opcount); uma iteração simples sobre as linhas no arquivo ( simplecount); readline com um arquivo mapeado na memória (mmap) ( mapcount); e a solução de leitura de buffer oferecida por Mykola Kharechko ( bufcount).

Executei cada função cinco vezes e calculei o tempo médio de execução para um arquivo de texto de 1,2 milhão de linhas.

Windows XP, Python 2.5, 2 GB de RAM, processador AMD de 2 GHz

Aqui estão os meus resultados:

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

Edit : números para Python 2.6:

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

Portanto, a estratégia de leitura de buffer parece ser a mais rápida para Windows / Python 2.6

Aqui está o código:

from __future__ import with_statement
import time
import mmap
import random
from collections import defaultdict

def mapcount(filename):
    f = open(filename, "r+")
    buf = mmap.mmap(f.fileno(), 0)
    lines = 0
    readline = buf.readline
    while readline():
        lines += 1
    return lines

def simplecount(filename):
    lines = 0
    for line in open(filename):
        lines += 1
    return lines

def bufcount(filename):
    f = open(filename)                  
    lines = 0
    buf_size = 1024 * 1024
    read_f = f.read # loop optimization

    buf = read_f(buf_size)
    while buf:
        lines += buf.count('\n')
        buf = read_f(buf_size)

    return lines

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


counts = defaultdict(list)

for i in range(5):
    for func in [mapcount, simplecount, bufcount, opcount]:
        start_time = time.time()
        assert func("big_file.txt") == 1209138
        counts[func].append(time.time() - start_time)

for key, vals in counts.items():
    print key.__name__, ":", sum(vals) / float(len(vals))
Ryan Ginstrom
fonte
1
O arquivo inteiro mapeado na memória não é carregado na memória. Você obtém um espaço de memória virtual, no qual o sistema operacional troca e entra na RAM, conforme necessário. Veja como eles estão tratadas no Windows: msdn.microsoft.com/en-us/library/ms810613.aspx
Ryan Ginstrom
1
Desculpe, aqui está uma referência mais geral sobre arquivos mapeados na memória: en.wikipedia.org/wiki/Memory-mapped_file E obrigado pela votação. :)
Ryan Ginstrom
1
Mesmo que seja apenas uma memória virtual, é exatamente o que limita essa abordagem e, portanto, não funciona em arquivos enormes. Eu tentei com ~ 1,2 Gb arquivo com mais de 10 mln. linhas (conforme obtido com wc -l) e acabou de obter um WindowsError: [Erro 8] Não há armazenamento suficiente disponível para processar este comando. claro, este é um caso de ponta.
SilentGhost
6
+1 para dados de tempo real. Sabemos se o tamanho do buffer de 1024 * 1024 é ideal ou existe um melhor?
19410 Kiv
28
Parece que wccount()é o mais rápido gist.github.com/0ac760859e614cd03652
jfs
133

Eu tive que postar isso em uma pergunta semelhante até que minha pontuação de reputação subisse um pouco (graças a quem me bateu!).

Todas essas soluções ignoram uma maneira de tornar essa execução consideravelmente mais rápida, usando a interface não armazenada em buffer (bruta), usando bytearrays e fazendo seu próprio buffer. (Isso só se aplica no Python 3. No Python 2, a interface bruta pode ou não ser usada por padrão, mas no Python 3, você usará o Unicode como padrão.)

Usando uma versão modificada da ferramenta de temporização, acredito que o código a seguir é mais rápido (e marginalmente mais pitônico) do que qualquer uma das soluções oferecidas:

def rawcount(filename):
    f = open(filename, 'rb')
    lines = 0
    buf_size = 1024 * 1024
    read_f = f.raw.read

    buf = read_f(buf_size)
    while buf:
        lines += buf.count(b'\n')
        buf = read_f(buf_size)

    return lines

Usando uma função de gerador separada, isso executa um smidge mais rápido:

def _make_gen(reader):
    b = reader(1024 * 1024)
    while b:
        yield b
        b = 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 )

Isso pode ser feito completamente com expressões de geradores in-line usando itertools, mas fica muito estranho:

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 )

Aqui estão os meus horários:

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
Michael Bacon
fonte
20
Estou trabalhando com arquivos de 100 Gb + e suas contas brutas são a única solução viável que vi até agora. Obrigado!
soungalo
1
está wccountnesta tabela para a wcferramenta de shell do subprocesso ?
Anentropic
1
encontrei isso em outro comentário, acho que é então gist.github.com/zed/0ac760859e614cd03652
Anentropic
3
Obrigado @ michael-bacon, é uma solução muito boa. Você pode tornar a rawincountsolução menos esquisita usando em bufgen = iter(partial(f.raw.read, 1024*1024), b'')vez de combinar takewhilee repeat.
Peter H.
1
Oh, função parcial, sim, isso é um belo pequeno ajuste. Além disso, eu assumi que o 1024 * 1024 seria mesclado pelo intérprete e tratado como uma constante, mas isso não estava documentado.
Michael Bacon
90

Você pode executar um subprocesso e executar wc -l filename

import subprocess

def 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])
Ólafur Waage
fonte
6
qual seria a versão do windows para isso?
SilentGhost
1
Você pode se referir a essa pergunta sobre isso. stackoverflow.com/questions/247234/…
Ólafur Waage
7
De fato, no meu caso (Mac OS X), isso leva 0,13 s contra 0,5 s para contar o número de linhas "para x no arquivo (...)" produz, contra 1,0 s contando chamadas repetidas para str.find ou mmap.find . (O arquivo que eu usei para testar isso tem 1,3 milhão de linhas.) #
22415
1
Não há necessidade de envolver a concha nisso. resposta editada e código de exemplo adicionado;
Nosklo 11/05/09
2
Não é multiplataforma.
e-info128
42

Aqui está um programa python para usar a biblioteca de multiprocessamento para distribuir a contagem de linhas entre máquinas / núcleos. Meu teste melhora a contagem de um arquivo de linha de 20 milhões de 26 segundos para 7 segundos usando um servidor Windows 64 de 8 núcleos. Nota: não usar o mapeamento de memória torna as coisas muito mais lentas.

import multiprocessing, sys, time, os, mmap
import logging, logging.handlers

def init_logger(pid):
    console_format = 'P{0} %(levelname)s %(message)s'.format(pid)
    logger = logging.getLogger()  # New logger at root level
    logger.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 counting

    fSize = os.stat(file1).st_size
    chunk = (fSize / processes) + 1

    lines = 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 += 1

    if _seedStart < int(seekStart + 1):
        seekStart += 1

    if seekEnd > fSize:
        seekEnd = fSize

    #find where to start
    if pid > 0:
        m1.seek( seekStart )
        #read next line
        l1 = m1.readline()  # need to use readline with memory mapped files
        seekStart = m1.tell()

    #tell previous rank my seek start to make their seek end

    if 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 += 1
        l1 = m1.readline()
        if m1.tell() > seekEnd or len(l1) == 0:
            break

    logging.info( 'done' )
    # add up the results
    if pid == 0:
        for p in range(1,processes):
            lines += queues[0].get()
        queues[0].put(lines) # the total lines counted
    else:
        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 process
    for pid in range(processes):
        queues.append( multiprocessing.Queue() )
    jobs=[]
    prev_pipe = 0
    for 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 finish
    lines = queues[0].get()

    logging.info( 'finished {} Lines:{}'.format( time.time() - t, lines ) )
Martlark
fonte
Como isso funciona com arquivos muito maiores que a memória principal? por exemplo, um arquivo de 20GB em um sistema com 4 GB de RAM e 2 núcleos
Brian Minton
Difícil de testar agora, mas presumo que pagine o arquivo dentro e fora.
Martlark
5
Este é um código bem legal. Fiquei surpreso ao descobrir que é mais rápido usar vários processadores. Imaginei que o IO seria o gargalo. Nas versões antigas do Python, linha 21 necessidades int () como pedaço = int ((FSIZE / processos)) + 1
Karl Henselin
ele carrega todo o arquivo na memória? que tal um incêndio maior em que o tamanho é maior que o da ram no computador?
Pelos
Os arquivos são mapeados na memória virtual; portanto, o tamanho do arquivo e a quantidade de memória real geralmente não são uma restrição.
Martlark
17

Uma solução bash de uma linha semelhante a esta resposta , usando a subprocess.check_outputfunção moderna :

def line_count(filename):
    return int(subprocess.check_output(['wc', '-l', filename]).split()[0])
1 ''
fonte
Esta resposta deve ser votada para um ponto mais alto neste segmento para usuários de Linux / Unix. Apesar das preferências majoritárias em uma solução de plataforma cruzada, essa é uma maneira excelente no Linux / Unix. Para um arquivo CSV de 184 milhões de linhas em que preciso coletar dados, ele fornece o melhor tempo de execução. Outras soluções python puras demoram em média mais de 100 segundos, enquanto a chamada de subprocesso wc -lleva aproximadamente 5 segundos.
Shan Dou
shell=Trueé ruim para a segurança, é melhor evitá-lo.
Alexey Vazhnov
Ponto justo, editado
1 ''
15

Eu usaria o método de objeto de arquivo do Python readlines, da seguinte maneira:

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

Isso abre o arquivo, cria uma lista de linhas no arquivo, conta o comprimento da lista, salva isso em uma variável e fecha o arquivo novamente.

Daniel Lee
fonte
6
Embora essa seja uma das primeiras maneiras que vem à mente, provavelmente não é muito eficiente em termos de memória, especialmente se contar linhas em arquivos de até 10 GB (como eu faço), o que é uma desvantagem notável.
Steen Schütt
@TimeSheep Esse é um problema para arquivos com muitos (digamos, bilhões) de linhas pequenas ou arquivos com linhas extremamente longas (digamos, Gigabytes por linha)?
22618 Robert
A razão pela qual pergunto é: parece que o compilador deve ser capaz de otimizar isso sem criar uma lista intermediária.
22618 Robert
@dmityugov Por documentos em Python, xreadlinesestá obsoleto desde a versão 2.3, pois apenas retorna um iterador. for line in fileé a substituição declarada. Veja: docs.python.org/2/library/stdtypes.html#file.xreadlines
Kumba
12
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
pkit
fonte
12

Aqui está o que eu uso, parece bastante limpo:

import subprocess

def 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])

ATUALIZAÇÃO: Isso é marginalmente mais rápido do que usar python puro, mas ao custo do uso de memória. O subprocesso bifurcará um novo processo com o mesmo espaço de memória que o processo pai enquanto ele executa seu comando.

Radtek
fonte
1
Apenas como uma observação lateral, isso não funcionará no Windows, é claro.
Bram Vanroy
aparentemente os utilitários principais fornecem "wc" para windows stackoverflow.com/questions/247234/… . Você também pode usar uma VM linux na sua caixa do Windows se o seu código acabar sendo executado no linux no prod.
Radtek 25/02/19
Ou WSL, altamente recomendado sobre qualquer VM, se coisas como essa são a única coisa que você faz. :-)
Bram Vanroy 25/02/19
Sim, isso funciona. Eu não sou um cara janelas, mas a partir goolging eu aprendi WSL = Windows Subsistema para Linux =)
radtek
3
python3.7: subprocess retorna bytes, então o código fica assim: int (subprocess.check_output (['wc', '-l', file_path]). decode ("utf-8"). lstrip (). split (" ") [0])
Alexey Alexeenka
11

Esta é a coisa mais rápida que eu encontrei usando python puro. Você pode usar a quantidade de memória desejada configurando o buffer, embora 2 ** 16 pareça ser um ponto ideal no meu computador.

from functools import partial

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

Encontrei a resposta aqui Por que a leitura de linhas do stdin é muito mais lenta em C ++ que no Python? e ajustou um pouquinho. É uma leitura muito boa para entender como contar linhas rapidamente, embora wc -lainda seja 75% mais rápido do que qualquer outra coisa.

jeffpkamp
fonte
9

Eu obtive uma pequena melhoria (4-8%) com esta versão que reutiliza um buffer constante para evitar qualquer sobrecarga de memória ou GC:

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

Você pode brincar com o tamanho do buffer e talvez ver uma pequena melhoria.

Scott Persinger
fonte
Agradável. Para conta para arquivos que não terminam em \ n, adicione 1 fora do loop se buffer e buffer [-1] = '\ n'!
ryuusenshi
Um erro: o buffer na última rodada pode não estar limpo.
Jay
e se entre os buffers uma parte terminar com \ e a outra parte começar com n? que vai perder uma nova linha de lá, eu sudgest a variáveis para armazenar o fim e no início de cada pedaço, mas que pode adicionar mais tempo para o script = (
Pelos
9

Resposta de Kyle

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

provavelmente é o melhor, uma alternativa para isso é

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

Aqui está a comparação do desempenho de ambos

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

In [21]: timeit len(open('Charts.ipynb').read().splitlines())
100000 loops, best of 3: 12 µs per loop
ChillarAnand
fonte
9

Solução de uma linha:

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

Meu trecho:

>>> os.system('wc -l *.txt')

0 bar.txt
1000 command.txt
3 test_file.txt
1003 total
O Exorcista
fonte
Boa ideia, infelizmente isso não funciona no Windows.
Kim
3
Se você quer ser surfista de python, diga adeus ao windows. Acredite em mim que você vai me agradecer um dia.
TheExorcist
6
Eu apenas considerei digno de nota que isso só funcionará no Windows. Eu prefiro trabalhar em uma pilha linux / unix, mas ao escrever o IMHO de software, deve-se considerar os efeitos colaterais que um programa pode ter quando executado em diferentes sistemas operacionais. Como o OP não mencionou sua plataforma e, caso alguém apareça nessa solução pelo google e a copie (sem saber das limitações que um sistema Windows pode ter), eu queria adicionar a nota.
Kim
Você não pode salvar a saída os.system()em variável e pós-processá-la de qualquer maneira.
An Se
@AnSe você está correto, mas a pergunta não é perguntada se salva ou não.Eu acho que você está entendendo o contexto.
TheExorcist 16/01
6

Apenas para concluir os métodos acima, tentei uma variante com o módulo fileinput:

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

E passou um arquivo de linhas de 60mil para todos os métodos acima mencionados:

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

É uma pequena surpresa para mim que a entrada de arquivo seja tão ruim e tenha uma escala muito pior do que todos os outros métodos ...

BandGap
fonte
5

Quanto a mim, essa variante será a mais rápida:

#!/usr/bin/env python

def main():
    f = open('filename')                  
    lines = 0
    buf_size = 1024 * 1024
    read_f = f.read # loop optimization

    buf = read_f(buf_size)
    while buf:
        lines += buf.count('\n')
        buf = read_f(buf_size)

    print lines

if __name__ == '__main__':
    main()

razões: armazenar em buffer mais rapidamente do que ler linha por linha e string.counttambém é muito rápido

Mykola Kharechko
fonte
1
Mas é isso? Pelo menos no OSX / python2.5, a versão do OP ainda é 10% mais rápida, de acordo com timeit.py.
dF.
E se a última linha não terminar em '\ n'?
Tzot 11/05/09
1
Não sei como você o testou, dF, mas na minha máquina é ~ 2,5 vezes mais lento que qualquer outra opção.
SilentGhost
34
Você afirma que será o mais rápido e depois não o testou. Não é muito científico, né? :)
Ólafur Waage
Veja a solução e as estatísticas fornecidas por Ryan Ginstrom, abaixo. Verifique também o comentário de JF Sebastian e o link para a mesma resposta.
SherylHohman
5

Este código é mais curto e mais claro. Provavelmente é a melhor maneira:

num_lines = open('yourfile.ext').read().count('\n')
Texom512
fonte
6
Você também deve fechar o arquivo.
rsm
6
Ele carregará o arquivo inteiro na memória.
Ivelin
não é melhor quando precisar de desempenho em arquivos grandes
mabraham 23/03
4

Eu modifiquei o caso do buffer assim:

def CountLines(filename):
    f = open(filename)
    try:
        lines = 1
        buf_size = 1024 * 1024
        read_f = f.read # loop optimization
        buf = read_f(buf_size)

        # Empty file
        if not buf:
            return 0

        while buf:
            lines += buf.count('\n')
            buf = read_f(buf_size)

        return lines
    finally:
        f.close()

Agora também os arquivos vazios e a última linha (sem \ n) são contados.

Manequim
fonte
Talvez também explique (ou adicione um comentário no código) o que você mudou e para quê;). Pode facilitar muito mais as pessoas que estão dentro do seu código (em vez de "analisar" o código no cérebro).
perfil completo de Styxxy
Acho que a otimização do loop permite que o Python faça uma pesquisa de variável local em read_f, python.org/doc/essays/list2str
The Red Pea
3

Que tal isso

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

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

pyanon
fonte
Isso fornece a contagem -1 do valor verdadeiro.
Borealis
O segundo argumento opcional para enumerate()é a contagem de início, de acordo com docs.python.org/2/library/functions.html#enumerate
MarkHu
3
print open('file.txt', 'r').read().count("\n") + 1
Andrés Torres
fonte
3
def line_count(path):
    count = 0
    with open(path) as lines:
        for count, l in enumerate(lines, start=1):
            pass
    return count
mdwhatcott
fonte
3

Se alguém quiser obter a contagem de linhas mais barata no Python no Linux, recomendo este método:

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

file_path pode ser o caminho abstrato do arquivo ou o caminho relativo. Espero que isso possa ajudar.

Lerner Zhang
fonte
2

Que tal agora?

import fileinput
import sys

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

fileinput.close()
print counter
leba-lev
fonte
2

Que tal esse one-liner:

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

Demora 0,003 segundos usando esse método para cronometrar em um arquivo de linha 3900

def c():
  import time
  s = time.time()
  file_length = len(open('myfile.txt','r').read().split('\n'))
  print time.time() - s
onetwopunch
fonte
2
def count_text_file_lines(path):
    with open(path, 'rt') as file:
        line_count = sum(1 for _line in file)
    return line_count
jciloa
fonte
Poderia, por favor, explicar o que há de errado com isso, se você acha que está errado? Funcionou para mim. Obrigado!
jciloa
Eu também estaria interessado em saber por que essa resposta foi rebaixada. Ele itera sobre o arquivo por linhas e as resume. Eu gosto, é curto e direto ao ponto, o que há de errado com isso?
cessora
2

Método simples:

1)

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

430

2)

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

3)

num_lines = len(list(open('myfile.txt')))
Mohideen bin Mohammed
fonte
3
Neste arquivo de exemplo não está fechado.
26719 Maciej M
9
O OP queria algo com eficiência de memória. Definitivamente não é isso.
Andy Carlson
1

o resultado da abertura de um arquivo é um iterador, que pode ser convertido em uma sequência com um comprimento:

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

isso é mais conciso do que seu loop explícito e evita o enumerate.

Andrew Jaffe
fonte
10
o que significa que um arquivo de 100 Mb precisará ser lido na memória.
SilentGhost
Sim, bom ponto, embora eu me pergunte sobre a diferença de velocidade (em oposição à memória). Provavelmente é possível criar um iterador que faça isso, mas acho que seria equivalente à sua solução.
10139 Andrew Jaffe
6
-1, não é apenas a memória, mas a construção da lista na memória.
orip 21/09/09
0

Você pode usar o os.pathmódulo da seguinte maneira:

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

, onde Filenameé o caminho absoluto do arquivo.

Vencedor
fonte
1
O que essa resposta tem a ver os.path?
moi
0

Se o arquivo puder caber na memória,

with open(fname) as f:
    count = len(f.read().split(b'\n')) - 1
Karthik
fonte