Come ottenere il conteggio delle righe di un file di grandi dimensioni in modo economico in Python?


1012

Devo ottenere un conteggio delle righe di un file di grandi dimensioni (centinaia di migliaia di righe) in Python. Qual è il modo più efficiente sia in termini di memoria che di tempo?

Al momento faccio:

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

è possibile fare di meglio?


7
È necessario il conteggio esatto delle righe o sarà sufficiente un'approssimazione?
pico,

43
Vorrei aggiungere i = -1 prima per il ciclo, poiché questo codice non funziona per i file vuoti.
Maciek Sawicki,

12
@Legend: Scommetto che pico sta pensando, ottieni la dimensione del file (con seek (0,2) o equiv), dividi per la lunghezza approssimativa della linea. All'inizio potresti leggere alcune righe per indovinare la lunghezza media della riga.
Anne,

32
enumerate(f, 1)e mollare il i + 1?
Ian Mackinnon,

4
@IanMackinnon Funziona per file vuoti, ma devi inizializzare i su 0 prima del for-loop.
scai,

Risposte:


357

Non puoi fare di meglio.

Dopotutto, qualsiasi soluzione dovrà leggere l'intero file, capire quanti \n ne hai e restituire quel risultato.

Hai un modo migliore per farlo senza leggere l'intero file? Non sono sicuro ... La migliore soluzione sarà sempre legata all'I / O, la cosa migliore che puoi fare è assicurarti di non usare memoria non necessaria, ma sembra che tu ne abbia coperto.


7
Esattamente, anche WC sta leggendo il file, ma in C ed è probabilmente abbastanza ottimizzato.
Ólafur Waage,

6
Per quanto ho capito, il file Python IO viene eseguito anche tramite C. docs.python.org/library/stdtypes.html#file-objects
Tomalak

9
@Tomalak È un'aringa rossa. Mentre python e wc potrebbero emettere le stesse syscalls, python ha un overhead di invio del codice operativo che wc non ha.
bobpoekert,

4
È possibile approssimare un conteggio di linee campionando. Può essere migliaia di volte più veloce. Vedi: documentroot.com/2011/02/…
Erik Aronesty,

4
Altre risposte sembrano indicare che questa risposta categorica è errata e dovrebbe pertanto essere eliminata anziché mantenuta come accettata.
Skippy le Grand Gourou,

625

Una riga, probabilmente abbastanza veloce:

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

8
è simile alla somma (sequenza di 1) ogni riga conta come 1. >>> [1 per riga nell'intervallo (10)] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] >>> somma (1 per la riga nell'intervallo (10)) 10 >>>
James Sapam il

4
num_lines = sum (1 per riga aperta ('myfile.txt') if line.rstrip ()) per filtro righe vuote
Honghe.Wu

61
quando apriamo un file, questo verrà chiuso automaticamente una volta ripetuti tutti gli elementi? È necessario 'close ()'? Penso che non possiamo usare 'with open ()' in questa breve affermazione, giusto?
Mannaggia,

16
@Mannaggia hai ragione, sarebbe meglio usare 'with open (nomefile)' per essere sicuro che il file si chiuda quando fatto, e ancora meglio lo sta facendo all'interno di un blocco try-tranne, dove viene generata l'eccezione e IOError se il file non può essere aperto.
BoltzmannBrain

17
Un'altra cosa da notare: Questo è ~ 0.04-0.05 secondi più lento rispetto a quello del problema originale dava su un file di testo 300 mila linea
Andrew

202

Credo che un file mappato in memoria sarà la soluzione più veloce. Ho provato quattro funzioni: la funzione pubblicata dall'OP ( opcount); una semplice iterazione sopra le righe nel file ( simplecount); readline con un file mappato in memoria (mmap) ( mapcount); e la soluzione di lettura del buffer offerta da Mykola Kharechko (bufcount ).

Ho eseguito ciascuna funzione cinque volte e ho calcolato il tempo di esecuzione medio per un file di testo di 1,2 milioni di righe.

Windows XP, Python 2.5, 2 GB di RAM, processore AMD da 2 GHz

Ecco i miei risultati:

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

Modifica : numeri per Python 2.6:

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

Quindi la strategia di lettura del buffer sembra essere la più veloce per Windows / Python 2.6

Ecco il codice:

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

1
L'intero file mappato in memoria non viene caricato in memoria. Si ottiene uno spazio di memoria virtuale, che il sistema operativo scambia dentro e fuori dalla RAM secondo necessità. Ecco come vengono gestiti su Windows: msdn.microsoft.com/en-us/library/ms810613.aspx
Ryan Ginstrom,

1
Siamo spiacenti, ecco un riferimento più generale sui file mappati in memoria: en.wikipedia.org/wiki/Memory-mapped_file E grazie per il voto. :)
Ryan Ginstrom,

1
Anche se è solo una memoria virtuale, è precisamente ciò che limita questo approccio e quindi non funzionerà con file di grandi dimensioni. L'ho provato con ~ 1,2 GB di file con oltre 10 mln. righe (come ottenuto con wc -l) e appena ricevuto un errore Windows: [Errore 8] Non è disponibile memoria sufficiente per elaborare questo comando. ovviamente, questo è un caso limite.
SilentGhost,

6
+1 per dati di temporizzazione reali. Sappiamo se la dimensione del buffer di 1024 * 1024 è ottimale o ce n'è una migliore?
Kiv,

28
Sembra che wccount()sia il più veloce gist.github.com/0ac760859e614cd03652
jfs

133

Ho dovuto postare questo su una domanda simile fino a quando il mio punteggio di reputazione è saltato un po '(grazie a chiunque mi abbia urtato!).

Tutte queste soluzioni ignorano un modo per rendere questa corsa considerevolmente più veloce, vale a dire usando l'interfaccia senza buffer (raw), usando i bytearrays e facendo il tuo buffering. (Ciò si applica solo in Python 3. In Python 2, l'interfaccia non elaborata può essere utilizzata o meno per impostazione predefinita, ma in Python 3, verrà impostato automaticamente Unicode.)

Utilizzando una versione modificata dello strumento di cronometraggio, credo che il seguente codice sia più veloce (e marginalmente più pitonico) di qualsiasi delle soluzioni offerte:

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

Utilizzando una funzione di generatore separata, questo fa funzionare un fumo più velocemente:

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 )

Questo può essere fatto completamente con le espressioni dei generatori in linea usando itertools, ma diventa piuttosto strano:

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 )

Ecco i miei tempi:

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

20
Sto lavorando con file 100 Gb + e i tuoi rawgencounts sono l'unica soluzione possibile che ho visto finora. Grazie!
Soungalo,

1
è wccountin questa tabella per lo wcstrumento shell sottoprocesso ?
Anentropico

1
trovato questo in un altro commento, suppongo che sia poi gist.github.com/zed/0ac760859e614cd03652
Anentropic

3
Grazie @ michael-bacon, è davvero una bella soluzione. Puoi rendere la rawincountsoluzione meno strana dall'aspetto usando bufgen = iter(partial(f.raw.read, 1024*1024), b'')invece di combinare takewhilee repeat.
Peter H.

1
Oh, funzione parziale, sì, è una piccola modifica. Inoltre, supponevo che il 1024 * 1024 sarebbe stato unito dall'interprete e trattato come una costante, ma che era in un sospetto non documentazione.
Michael Bacon,

90

È possibile eseguire un sottoprocesso ed eseguire 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])

6
quale sarebbe la versione Windows di questo?
SilentGhost,

1
È possibile fare riferimento a questa domanda SO al riguardo. stackoverflow.com/questions/247234/…
Ólafur Waage

7
In effetti, nel mio caso (Mac OS X) questo richiede 0,13s contro 0,5s per contare il numero di righe "per x nel file (...)" produce, rispetto a 1.0s contando le chiamate ripetute a str.find o mmap.find . (Il file che ho usato per testare ha 1,3 milioni di righe.)
Bendin,

1
Non è necessario coinvolgere la shell su questo. risposta modificata e codice di esempio aggiunto;
nosklo,

2
Non è multipiattaforma.
e-info128,

42

Ecco un programma Python per usare la libreria multiprocessing per distribuire il conteggio delle linee su macchine / core. Il mio test migliora il conteggio di un file di 20 milioni di righe da 26 secondi a 7 secondi utilizzando un server Windows 64 a 8 core. Nota: non usare la mappatura della memoria rende le cose molto più lente.

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

Come funziona con file molto più grandi della memoria principale? ad esempio un file da 20 GB su un sistema con 4 GB di RAM e 2 core
Brian Minton,

Difficile da testare ora, ma presumo che farebbe scorrere il file dentro e fuori.
Martlark,

5
Questo è un codice piuttosto accurato. Sono stato sorpreso di scoprire che è più veloce utilizzare più processori. Ho pensato che l'IO sarebbe stato il collo di bottiglia. Nelle versioni precedenti di Python, la riga 21 richiede int () come chunk = int ((fSize / processi)) + 1
Karl Henselin,

carica tutto il file in memoria? che dire di un incendio più grande in cui le dimensioni sono più grandi del montone sul computer?
pelos,

I file vengono mappati nella memoria virtuale, quindi la dimensione del file e la quantità di memoria effettiva non sono generalmente una restrizione.
Martlark,

17

Una soluzione bash a una riga simile a questa risposta , utilizzando la subprocess.check_outputfunzione moderna :

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

Questa risposta dovrebbe essere votata al primo posto in questa discussione per gli utenti Linux / Unix. Nonostante le preferenze della maggioranza in una soluzione multipiattaforma, questo è un modo eccellente su Linux / Unix. Per un file csv di 184 milioni di righe da cui devo campionare i dati, fornisce il miglior tempo di esecuzione. Altre soluzioni Python pure richiedono in media oltre 100 secondi, mentre la chiamata di sottoprocesso wc -ldura circa 5 secondi.
Shan Dou,

shell=Truefa male alla sicurezza, è meglio evitarlo.
Alexey Vazhnov,

Fair point, modificato
1 ''

15

Vorrei utilizzare il metodo oggetto file di Python readlines, come segue:

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

Questo apre il file, crea un elenco di righe nel file, conta la lunghezza dell'elenco, lo salva in una variabile e chiude nuovamente il file.


6
Anche se questo è uno dei primi modi in cui viene in mente, probabilmente non è molto efficiente in termini di memoria, soprattutto se si contano le righe in file fino a 10 GB (come faccio io), il che è uno svantaggio notevole.
Steen Schütt,

@TimeSheep È un problema per i file con molti (diciamo, miliardi) di piccole righe o file che hanno linee estremamente lunghe (diciamo, Gigabyte per riga)?
Robert

Il motivo per cui lo chiedo è che il compilatore dovrebbe essere in grado di ottimizzarlo senza creare un elenco intermedio.
Robert

@dmityugov Per documenti Python, xreadlinesè stato deprecato dal 2.3, in quanto restituisce solo un iteratore. for line in fileè la sostituzione dichiarata. Vedi: 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

12

Ecco quello che uso, sembra abbastanza pulito:

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

AGGIORNAMENTO: Questo è leggermente più veloce rispetto all'utilizzo di Python puro ma a costo dell'uso della memoria. Il sottoprocesso eseguirà il fork di un nuovo processo con lo stesso footprint di memoria del processo parent mentre esegue il comando.


1
Come nota a margine, ovviamente non funzionerà su Windows.
Bram Vanroy,

apparentemente core utils fornisce "wc" per windows stackoverflow.com/questions/247234/… . Puoi anche usare una VM Linux nella tua finestra di Windows se il tuo codice finirà per essere eseguito in Linux in prod.
Radtek,

O WSL, altamente consigliato su qualsiasi VM se cose come questa sono l'unica cosa che fai. :-)
Bram Vanroy,

Sì, funziona. Non sono un tipo Windows ma da sciocchezze ho imparato WSL = sottosistema Windows per Linux =)
radtek,

3
python3.7: byte di ritorno sottoprocesso, quindi il codice è simile al seguente: int (subprocess.check_output (['wc', '-l', percorso_file]). decode ("utf-8"). lstrip (). split (" ") [0])
Alexey Alexeenka il

11

Questa è la cosa più veloce che ho trovato usando il puro pitone. È possibile utilizzare la quantità di memoria desiderata impostando il buffer, anche se 2 ** 16 sembra essere un punto debole sul mio computer.

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

Ho trovato la risposta qui Perché la lettura di righe da stdin è molto più lenta in C ++ di Python? e lo ha modificato solo leggermente. È un'ottima lettura per capire come contare rapidamente le linee, anche se wc -lè ancora circa il 75% più veloce di ogni altra cosa.


9

Ho ottenuto un piccolo miglioramento (4-8%) con questa versione che riutilizza un buffer costante in modo da evitare qualsiasi sovraccarico di memoria o GC:

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

Puoi giocare con la dimensione del buffer e forse vedere un piccolo miglioramento.


Bello. Per tenere conto dei file che non finiscono in \ n, aggiungi 1 al di fuori del ciclo se buffer e buffer [-1]! = '\ N'
ryuusenshi

Un bug: il buffer nell'ultimo round potrebbe non essere pulito.
Jay,

cosa succede se tra i buffer una parte termina con \ e l'altra parte inizia con n? che mi mancherà una nuova riga, scrivo più a sud per le variabili per memorizzare la fine e l'inizio di ogni blocco, ma ciò potrebbe aggiungere più tempo allo script = (
pelos

9

La risposta di Kyle

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

è probabilmente il migliore, un'alternativa per questo è

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

Ecco il confronto delle prestazioni di entrambi

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

9

Una soluzione di linea:

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

Il mio frammento:

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

0 bar.txt
1000 command.txt
3 test_file.txt
1003 total

Buona idea, sfortunatamente non funziona su Windows.
Kim,

3
se vuoi essere surfista di Python, saluta Windows. Credimi, mi ringrazierai un giorno.
esorcista il

6
Ho appena considerato degno di nota che questo funzionerà solo su Windows. Preferisco lavorare su uno stack linux / unix da solo, ma quando si scrive il software IMHO si dovrebbero considerare gli effetti collaterali che un programma potrebbe avere quando eseguito su diversi sistemi operativi. Dato che l'OP non ha menzionato la sua piattaforma e nel caso qualcuno visualizzi questa soluzione tramite Google e la copi (inconsapevole delle limitazioni che potrebbe avere un sistema Windows), ho voluto aggiungere la nota.
Kim,

Non è possibile salvare l'output di os.system()in variabile e elaborarlo comunque.
Un

@AnSe hai ragione, ma la domanda non viene posta se si salva o no. Immagino che tu stia capendo il contesto.
esorcista il

6

Solo per completare i metodi sopra ho provato una variante con il modulo fileinput:

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

E ha passato un file di linee 60mil a tutti i metodi sopra indicati:

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

È una piccola sorpresa per me che fileinput sia così male e ridimensiona molto peggio di tutti gli altri metodi ...


5

Quanto a me questa variante sarà la più veloce:

#!/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()

motivi: buffering più veloce della lettura riga per riga ed string.countè anche molto veloce


1
Ma è? Almeno su OSX / python2.5 la versione dell'OP è ancora circa il 10% più veloce secondo timeit.py.
dF.

Cosa succede se l'ultima riga non termina con '\ n'?
martedì

1
Non so come lo hai provato, dF, ma sulla mia macchina è ~ 2,5 volte più lento di qualsiasi altra opzione.
SilentGhost,

34
Dichiari che sarà il più veloce e quindi dichiari di non averlo testato. Non molto scientifico eh? :)
Ólafur Waage

Vedi la soluzione e le statistiche fornite dalla risposta Ryan Ginstrom di seguito. Guarda anche il commento di JF Sebastian e collega la stessa risposta.
SherylHohman,

5

Questo codice è più breve e più chiaro. È probabilmente il modo migliore:

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

6
Dovresti anche chiudere il file.
rsm,

6
Caricherà l'intero file in memoria.
Ivelin,

non è meglio quando si necessita di prestazioni su file di grandi dimensioni
mabraham

4

Ho modificato il buffer case in questo modo:

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

Ora vengono contati anche i file vuoti e l'ultima riga (senza \ n).


Forse spiega anche (o aggiungi un commento nel codice) cosa hai cambiato e per cosa;). Potrebbe dare alle persone qualcosa in più nel tuo codice molto più semplice (piuttosto che "analizzare" il codice nel cervello).
Styxxy,

L'ottimizzazione del loop credo che permetta a Python di fare una ricerca delle variabili locali su read_f, python.org/doc/essays/list2str
The Red Pea,

3

Che dire di questo

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



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

3

Se si desidera ottenere il conteggio delle righe a buon mercato in Python in Linux, consiglio questo metodo:

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

file_path può essere sia percorso file astratto che percorso relativo. Spero che questo possa aiutare.


2

Cosa ne pensi di questo?

import fileinput
import sys

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

fileinput.close()
print counter

2

Che ne dici di questo one-liner:

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

Impiega 0,003 secondi usando questo metodo per cronometrarlo su un file di 3900 righe

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

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

Potresti spiegare cosa c'è che non va se pensi che sia sbagliato? Ha funzionato per me. Grazie!
jciloa,

Sarei interessato anche al motivo per cui anche questa risposta è stata sottovalutata. Esegue l'iterazione del file per righe e li somma. Mi piace, è breve e al punto, cosa c'è che non va?
cessatore

2

Metodo semplice:

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

3
In questo esempio il file non è chiuso.
Maciej M,

9
OP voleva qualcosa di efficiente nella memoria. Questo non è assolutamente.
Andy Carlson,

1

il risultato dell'apertura di un file è un iteratore, che può essere convertito in una sequenza, che ha una lunghezza:

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

questo è più conciso del tuo ciclo esplicito ed evita il enumerate.


10
ciò significa che il file da 100 Mb dovrà essere letto in memoria.
SilentGhost,

sì, buon punto, anche se mi chiedo la differenza di velocità (rispetto alla memoria). Probabilmente è possibile creare un iteratore che lo fa, ma penso che sarebbe equivalente alla tua soluzione.
Andrew Jaffe,

6
-1, non è solo la memoria, ma deve costruire l'elenco in memoria.
orip,

0

È possibile utilizzare il os.pathmodulo nel modo seguente:

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

, dove si Filenametrova il percorso assoluto del file.


1
Cosa c'entra questa risposta os.path?
moi,

0

Se il file può adattarsi alla memoria, quindi

with open(fname) as f:
    count = len(f.read().split(b'\n')) - 1
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.