¿Cómo obtener el recuento de líneas de un archivo grande a bajo precio en Python?

1012

Necesito obtener un recuento de líneas de un archivo grande (cientos de miles de líneas) en Python. ¿Cuál es la forma más eficiente de memoria y tiempo?

Por el momento lo hago:

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

¿Es posible hacerlo mejor?

SilentGhost
fuente
77
¿Necesita un recuento exacto de líneas o bastará una aproximación?
pico
43
Agregaría i = -1 antes para el bucle, ya que este código no funciona para archivos vacíos.
Maciek Sawicki
12
@Leyenda: apuesto a que pico está pensando, obtenga el tamaño del archivo (con seek (0,2) o equiv), divida por la longitud aproximada de la línea. Podrías leer algunas líneas al principio para adivinar la longitud promedio de la línea.
Anne
32
enumerate(f, 1)y deshacerse de la i + 1?
Ian Mackinnon
44
@IanMackinnon funciona para archivos vacíos, pero debe inicializar i a 0 antes del ciclo for.
scai

Respuestas:

357

No hay nada mejor que eso.

Después de todo, cualquier solución tendrá que leer el archivo completo, averiguar cuántos \ntiene y devolver ese resultado.

¿Tiene una mejor manera de hacerlo sin leer el archivo completo? No estoy seguro ... La mejor solución siempre estará vinculada a E / S, lo mejor que puede hacer es asegurarse de no usar memoria innecesaria, pero parece que tiene eso cubierto.

Yuval Adam
fuente
77
Exactamente, incluso WC está leyendo el archivo, pero en C y probablemente esté bastante optimizado.
Ólafur Waage
66
Por lo que yo entiendo, el archivo Python IO también se realiza a través de C. docs.python.org/library/stdtypes.html#file-objects
Tomalak
99
@Tomalak Eso es un arenque rojo. Mientras que python y wc podrían estar emitiendo las mismas llamadas de sistema, python tiene una sobrecarga de despacho de código de operación que wc no tiene.
bobpoekert
44
Puede aproximar un recuento de líneas por muestreo. Puede ser miles de veces más rápido. Ver: documentroot.com/2011/02/…
Erik Aronesty
44
Otras respuestas parecen indicar que esta respuesta categórica es incorrecta y, por lo tanto, debe eliminarse en lugar de mantenerse como se acepta.
Skippy le Grand Gourou
625

Una línea, probablemente bastante rápida:

num_lines = sum(1 for line in open('myfile.txt'))
Kyle
fuente
8
es similar a la suma (secuencia de 1) cada línea cuenta como 1. >>> [1 para la línea en el rango (10)] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] >>> sum (1 para línea en rango (10)) 10 >>>
James Sapam
44
num_lines = sum (1 para línea abierta ('myfile.txt') if line.rstrip ()) para filtrar líneas vacías
Honghe.Wu
61
a medida que abrimos un archivo, ¿se cerrará automáticamente una vez que iteremos sobre todos los elementos? ¿Es necesario 'cerrar ()'? Creo que no podemos usar 'con open ()' en esta breve declaración, ¿verdad?
Mannaggia
16
@Mannaggia estás en lo correcto, sería mejor usar 'con abrir (nombre de archivo)' para asegurarte de que el archivo se cierra cuando se hace, y aún mejor es hacerlo dentro de un bloque try-except, donde se lanza la excepción y IOError si El archivo no se puede abrir.
BoltzmannBrain
17
Otra cosa a tener en cuenta: esto es ~ 0.04-0.05 segundos más lento que el que dio el problema original en un archivo de texto de 300 mil líneas
Andrew
202

Creo que un archivo mapeado en memoria será la solución más rápida. Probé cuatro funciones: la función publicada por el OP ( opcount); una iteración simple sobre las líneas en el archivo ( simplecount); readline con un archivo mapeado en memoria (mmap) ( mapcount); y la solución de lectura de buffer ofrecida por Mykola Kharechko ( bufcount).

Ejecuté cada función cinco veces y calculé el tiempo de ejecución promedio para un archivo de texto de 1.2 millones de líneas.

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

Aquí están mis resultados:

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

Editar : números para Python 2.6:

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

Entonces, la estrategia de lectura del búfer parece ser la más rápida para Windows / Python 2.6

Aquí está el 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
fuente
1
Todo el archivo mapeado en memoria no se carga en la memoria. Obtiene un espacio de memoria virtual, que el sistema operativo intercambia dentro y fuera de la RAM según sea necesario. Así es como se manejan en Windows: msdn.microsoft.com/en-us/library/ms810613.aspx
Ryan Ginstrom
1
Lo sentimos, aquí hay una referencia más general sobre archivos mapeados en memoria: en.wikipedia.org/wiki/Memory-mapped_file Y gracias por la votación. :)
Ryan Ginstrom
1
Aunque es solo una memoria virtual, es precisamente lo que limita este enfoque y, por lo tanto, no funcionará para archivos de gran tamaño. Lo he probado con un archivo de ~ 1.2 Gb con más de 10 millones. líneas (como se obtiene con wc -l) y acabo de recibir un error de Windows: [Error 8] No hay suficiente almacenamiento disponible para procesar este comando. Por supuesto, este es un caso extremo.
SilentGhost
66
+1 para datos de tiempo real. ¿Sabemos si el tamaño del búfer de 1024 * 1024 es óptimo, o hay uno mejor?
Kiv
28
Parece que wccount()es el gist.github.com/0ac760859e614cd03652
jfs
133

Tuve que publicar esto en una pregunta similar hasta que mi puntaje de reputación aumentó un poco (¡gracias a quien me golpeó!).

Todas estas soluciones ignoran una forma de hacer que esto funcione considerablemente más rápido, es decir, usando la interfaz sin búfer (sin procesar), usando bytearrays y haciendo su propio almacenamiento en búfer. (Esto solo se aplica en Python 3. En Python 2, la interfaz en bruto puede o no usarse de manera predeterminada, pero en Python 3, usted usará Unicode de manera predeterminada).

Usando una versión modificada de la herramienta de sincronización, creo que el siguiente código es más rápido (y marginalmente más pitónico) que cualquiera de las soluciones ofrecidas:

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 una función de generador separada, esto ejecuta un smidge más 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 )

Esto se puede hacer completamente con expresiones de generadores en línea usando itertools, pero se ve bastante extraño:

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 )

Aquí están mis horarios:

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
fuente
20
Estoy trabajando con archivos de 100 Gb +, y sus recuentos sin procesar es la única solución factible que he visto hasta ahora. ¡Gracias!
soungalo
1
está wccounten esta tabla para la wcherramienta de shell de subproceso ?
Anentropic
1
Encontré esto en otro comentario, supongo que es entonces gist.github.com/zed/0ac760859e614cd03652
Anentropic
3
Gracias @ michael-bacon, es una muy buena solución. Puede hacer que la rawincountsolución tenga un aspecto menos extraño utilizando en bufgen = iter(partial(f.raw.read, 1024*1024), b'')lugar de combinar takewhiley repeat.
Peter H.
1
Oh, función parcial, sí, eso es un pequeño y agradable ajuste. Además, supuse que el intérprete fusionaría el 1024 * 1024 y lo trataría como una constante, pero eso no era documentación.
Michael Bacon
90

Podría ejecutar un subproceso y ejecutar 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
fuente
66
¿Cuál sería la versión de Windows de esto?
SilentGhost
1
Puede consultar esta pregunta SO con respecto a eso. stackoverflow.com/questions/247234/…
Ólafur Waage
77
De hecho, en mi caso (Mac OS X) esto toma 0.13s versus 0.5s para contar el número de líneas que "for x in file (...)" produce, versus 1.0s contando llamadas repetidas a str.find o mmap.find . (El archivo que usé para probar esto tiene 1.3 millones de líneas)
Bendin
1
No es necesario involucrar al shell en eso. respuesta editada y código de ejemplo agregado;
nosklo
2
No es plataforma cruzada.
e-info128
42

Aquí hay un programa de Python para usar la biblioteca de multiprocesamiento para distribuir el recuento de líneas entre máquinas / núcleos. Mi prueba mejora contando un archivo de línea de 20 millones de 26 segundos a 7 segundos usando un servidor Windows 64 de 8 núcleos. Nota: no usar el mapeo de memoria hace las cosas mucho más 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
fuente
¿Cómo funciona esto con archivos mucho más grandes que la memoria principal? por ejemplo, un archivo de 20 GB en un sistema con 4 GB de RAM y 2 núcleos
Brian Minton
Difícil de probar ahora, pero supongo que paginaría el archivo dentro y fuera.
Martlark
55
Este es un código bastante bueno. Me sorprendió descubrir que es más rápido usar múltiples procesadores. Pensé que el IO sería el cuello de botella. En versiones anteriores de Python, la línea 21 necesita int () como chunk = int ((fSize / procesos)) + 1
Karl Henselin
¿carga todo el archivo en la memoria? ¿Qué pasa con un incendio más grande donde el tamaño es mayor que el carnero en la computadora?
pelos
Los archivos se asignan a la memoria virtual, por lo que el tamaño del archivo y la cantidad de memoria real generalmente no es una restricción.
Martlark
17

Una solución bash de una línea similar a esta respuesta , utilizando la subprocess.check_outputfunción moderna :

def line_count(filename):
    return int(subprocess.check_output(['wc', '-l', filename]).split()[0])
1 ''
fuente
Esta respuesta debería votarse hasta un lugar más alto en este hilo para usuarios de Linux / Unix. A pesar de las preferencias de la mayoría en una solución multiplataforma, esta es una forma excelente en Linux / Unix. Para un archivo csv de 184 millones de líneas del que tengo que muestrear datos, proporciona el mejor tiempo de ejecución. Otras soluciones de Python puras tardan en promedio más de 100 segundos, mientras que la llamada de subprocesos wc -ltarda ~ 5 segundos.
Shan Dou
shell=Truees malo para la seguridad, es mejor evitarlo.
Alexey Vazhnov
Punto justo, editado
1 ''
15

Usaría el método de objeto de archivo de Python readlines, de la siguiente manera:

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

Esto abre el archivo, crea una lista de líneas en el archivo, cuenta la longitud de la lista, la guarda en una variable y cierra el archivo nuevamente.

Daniel Lee
fuente
66
Si bien esta es una de las primeras formas en que viene a la mente, probablemente no sea muy eficiente en la memoria, especialmente si se cuentan líneas en archivos de hasta 10 GB (como lo hago yo), lo cual es una desventaja notable.
Steen Schütt
@TimeSheep ¿Es este un problema para archivos con muchos (digamos, miles de millones) de líneas pequeñas o archivos que tienen líneas extremadamente largas (digamos, Gigabytes por línea)?
robert
La razón por la que pregunto es que parece que el compilador debería poder optimizar esto al no crear una lista intermedia.
robert
@dmityugov Por documentos de Python, xreadlinesha quedado en desuso desde 2.3, ya que solo devuelve un iterador. for line in filees el reemplazo indicado. Ver: 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
fuente
12

Esto es lo que uso, parece bastante limpio:

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

ACTUALIZACIÓN: Esto es marginalmente más rápido que usar Python puro pero a costa del uso de memoria. El subproceso bifurcará un nuevo proceso con la misma huella de memoria que el proceso principal mientras ejecuta su comando.

radtek
fuente
1
Solo como una nota al margen, esto no funcionará en Windows, por supuesto.
Bram Vanroy
Aparentemente, Core Utils proporciona "WC" para Windows stackoverflow.com/questions/247234/… . También puede usar una máquina virtual Linux en su cuadro de Windows si su código terminará ejecutándose en Linux en prod.
radtek
O WSL, muy recomendable sobre cualquier VM si cosas como esta es lo único que haces. :-)
Bram Vanroy
Si eso funciona. No soy un chico de Windows, pero aprendí WSL = Windows Subsystem for Linux =)
Radtek
3
python3.7: subproceso devuelve bytes, por lo que el código se ve así: int (subprocess.check_output (['wc', '-l', file_path]). decode ("utf-8"). lstrip (). split (" ") [0])
Alexey Alexeenka
11

Esto es lo más rápido que he encontrado usando Python puro. Puede usar la cantidad de memoria que desee configurando el búfer, aunque 2 ** 16 parece ser un punto ideal en mi computadora.

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), ''))

Encontré la respuesta aquí ¿Por qué leer líneas de stdin es mucho más lento en C ++ que Python? y lo ajusté solo un poquito. Es una muy buena lectura para entender cómo contar líneas rápidamente, aunque wc -ltodavía es aproximadamente un 75% más rápido que cualquier otra cosa.

jeffpkamp
fuente
9

Obtuve una pequeña mejora (4-8%) con esta versión que reutiliza un búfer constante, por lo que debería evitar cualquier memoria o sobrecarga del GC:

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

Puede jugar con el tamaño del búfer y tal vez ver una pequeña mejora.

Scott Persinger
fuente
Agradable. Para tener en cuenta los archivos que no terminan en \ n, agregue 1 fuera del ciclo si buffer y buffer [-1]! = '\ N'
ryuusenshi
Un error: el búfer en la última ronda podría no estar limpio.
Jay
¿Qué pasa si entre buffers una porción termina con \ y la otra porción comienza con n? que perderá una nueva línea allí, me gustaría utilizar variables para almacenar el final y el inicio de cada fragmento, pero eso podría agregar más tiempo al script = (
pelos
9

La respuesta de Kyle

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

es probablemente el mejor, una alternativa para esto es

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

Aquí está la comparación del rendimiento 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
fuente
9

Solución de una línea:

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

Mi fragmento:

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

0 bar.txt
1000 command.txt
3 test_file.txt
1003 total
El exorcista
fuente
Buena idea, desafortunadamente esto no funciona en Windows.
Kim
3
si quieres ser surfista de python, despídete de windows. Créeme, algún día me lo agradecerás.
TheExorcist
66
Solo consideré digno de mención que esto solo funcionará en Windows. Prefiero trabajar en una pila Linux / Unix, pero al escribir el software en mi humilde opinión, uno debería considerar los efectos secundarios que un programa podría tener cuando se ejecuta en diferentes sistemas operativos. Como el OP no mencionó su plataforma y en caso de que alguien aparezca en esta solución a través de Google y la copie (sin saber las limitaciones que podría tener un sistema Windows), quería agregar la nota.
Kim
No puede guardar la salida de la os.system()variable y procesarla de todos modos.
Un
@AnSe tiene razón, pero no se pregunta si se guarda o no. Supongo que está entendiendo el contexto.
TheExorcist
6

Solo para completar los métodos anteriores, probé una variante con el módulo de entrada de archivo:

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

Y pasó un archivo de líneas de 60mil a todos los métodos mencionados anteriormente:

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

Me sorprende un poco que la entrada de archivos sea tan mala y escale mucho peor que todos los demás métodos ...

BandGap
fuente
5

En cuanto a mí, esta variante será la más 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()

razones: almacenamiento en búfer más rápido que leer línea por línea y string.counttambién es muy rápido

Mykola Kharechko
fuente
1
¿Pero es? Al menos en OSX / python2.5, la versión del OP sigue siendo aproximadamente un 10% más rápida según timeit.py.
dF.
¿Qué pasa si la última línea no termina en '\ n'?
tzot
1
No sé cómo lo probaste, dF, pero en mi máquina es ~ 2.5 veces más lento que cualquier otra opción.
SilentGhost
34
Usted declara que será el más rápido y luego declara que no lo ha probado. No muy científico, ¿eh? :)
Ólafur Waage
Vea la solución y las estadísticas proporcionadas por la respuesta de Ryan Ginstrom a continuación. También mira el comentario de JF Sebastian y el enlace en la misma respuesta.
SherylHohman
5

Este código es más corto y más claro. Probablemente sea la mejor manera:

num_lines = open('yourfile.ext').read().count('\n')
Texom512
fuente
66
También debe cerrar el archivo.
rsm
66
Cargará todo el archivo en la memoria.
Ivelin
no es mejor cuando se necesita rendimiento en archivos grandes
mabraham
4

He modificado el caso del búfer así:

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()

Ahora también se cuentan los archivos vacíos y la última línea (sin \ n).

Tonto
fuente
Quizás también explique (o agregue un comentario en el código) qué cambió y para qué;). Podría dar a las personas algo más dentro de su código mucho más fácil (en lugar de "analizar" el código en el cerebro).
Styxxy
Creo que la optimización del bucle permite que Python realice una búsqueda de variables locales en read_f, python.org/doc/essays/list2str
The Red Pea
3

Que hay de esto

def file_len(fname):
  counts = itertools.count()
  with open(fname) as f: 
    for _ in f: counts.next()
  return counts.next()
Odwl
fuente
3
print open('file.txt', 'r').read().count("\n") + 1
Andrés Torres
fuente
3
def line_count(path):
    count = 0
    with open(path) as lines:
        for count, l in enumerate(lines, start=1):
            pass
    return count
mdwhatcott
fuente
3

Si uno quiere obtener el recuento de líneas a bajo costo en Python en Linux, recomiendo este método:

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

file_path puede ser una ruta de archivo abstracta o una ruta relativa. Espero que esto pueda ayudar.

Lerner Zhang
fuente
2

¿Qué tal esto?

import fileinput
import sys

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

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

¿Qué tal este one-liner:

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

Toma 0.003 segundos usando este método para cronometrarlo en un archivo de 3900 líneas

def c():
  import time
  s = time.time()
  file_length = len(open('myfile.txt','r').read().split('\n'))
  print time.time() - s
onetwopunch
fuente
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
fuente
¿Podría explicar qué tiene de malo si cree que está mal? Funcionó para mi. ¡Gracias!
jciloa
Me interesaría saber por qué esta respuesta también fue rechazada. Se itera sobre el archivo por líneas y las resume. Me gusta, es breve y al grano, ¿qué tiene de malo?
tasador
2

Método simple:

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
fuente
3
En este ejemplo, el archivo no está cerrado.
Maciej M
99
OP quería algo de memoria eficiente. Esto definitivamente no lo es.
Andy Carlson el
1

El resultado de abrir un archivo es un iterador, que se puede convertir en una secuencia, que tiene una longitud:

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

esto es más conciso que su ciclo explícito y evita el enumerate.

Andrew Jaffe
fuente
10
lo que significa que será necesario leer el archivo de 100 Mb en la memoria.
SilentGhost
sí, buen punto, aunque me pregunto acerca de la diferencia de velocidad (en oposición a la memoria). Probablemente sea posible crear un iterador que haga esto, pero creo que sería equivalente a su solución.
Andrew Jaffe
66
-1, no es solo la memoria, sino tener que construir la lista en la memoria.
orip
0

Puede usar el os.pathmódulo de la siguiente manera:

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

, donde Filenameestá la ruta absoluta del archivo.

Víctor
fuente
1
¿Con qué tiene que ver esta respuesta os.path?
moi
0

Si el archivo puede caber en la memoria, entonces

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