write with txt read for files create python text-files line-count

with - write to a file in python



¿Cómo obtener una cuenta de línea barata en Python? (30)

¿Por qué no leer las primeras 100 y las últimas 100 líneas y estimar la longitud promedio de la línea, luego dividir el tamaño total del archivo entre esos números? Si no necesita un valor exacto, esto podría funcionar.

Necesito obtener un conteo 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?

En el momento que hago:

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

¿Es posible hacerlo mejor?


¿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


¿Qué tal esto?

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


Aquí hay un programa de Python para usar la biblioteca de multiprocesamiento para distribuir el conteo de líneas a través de máquinas / núcleos. Mi prueba mejora el conteo de un archivo de 20 millones de líneas de 26 segundos a 7 segundos utilizando un servidor Windows 64 de 8 núcleos. Nota: no usar la asignación 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 ) )


Creo que un archivo mapeado en memoria será la solución más rápida. opcount 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 búfer 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

Edición : números para Python 2.6:

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

Así que la estrategia de lectura de 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))


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

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

esto es más conciso que su bucle explícito, y evita la enumerate .


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: el almacenamiento en búfer más rápido que leer línea por línea y string.count también es muy rápido


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

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


Esto es lo más rápido que he encontrado usando python puro. Puedes usar la cantidad de memoria que quieras configurando el búfer, aunque 2 ** 16 parece ser un punto dulce 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 en Python? y lo pellizcó un poquito. Es una muy buena lectura para entender cómo contar líneas rápidamente, aunque wc -l es aproximadamente un 75% más rápido que cualquier otra cosa.


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 ligeramente más rápido que usar python puro pero a costa del uso de la memoria. Subproceso procesará un nuevo proceso con la misma huella de memoria que el proceso primario mientras ejecuta su comando.


He modificado el caso de búfer de esta manera:

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


No puedes ser mejor que eso.

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

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


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

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

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


Otra posibilidad:

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


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


Que hay de esto

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


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

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

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


Similar:

lines = 0 with open(path) as f: for line in f: lines += 1


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

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

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

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

Es una pequeña sorpresa para mí que la entrada de archivos sea tan mala y se escale mucho peor que todos los otros métodos ...


Tuve que publicar esto en una pregunta similar hasta que mi puntuación de reputación saltó 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, mediante el uso de la interfaz sin búfer (en bruto), el uso de bytearrays y la creación de su propio almacenamiento en búfer. (Esto solo se aplica en Python 3. En Python 2, la interfaz sin formato puede o no usarse de manera predeterminada, pero en Python 3, se establecerá un valor predeterminado en Unicode).

Al usar una versión modificada de la herramienta de sincronización, creo que el siguiente código es más rápido (y ligeramente más pitón) 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 poco 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 raro:

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


Una línea, probablemente bastante rápida:

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


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

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


Yo usaría readlines método de objeto de archivo de Python, como sigue:

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 vuelve a cerrar el archivo.


una solución de 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


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


La respuesta de kyle

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

Es probablemente lo mejor, una alternativa para esto es

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

Aquí está la comparación de 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


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


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


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


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