¿Cómo puedo leer archivos de texto grandes línea por línea sin cargarlos en la memoria? [duplicate]

5 minutos de lectura

avatar de usuario
Bruno Rocha – rochacbruno

Quiero leer un archivo grande (>5 GB), línea por línea, sin cargar todo su contenido en la memoria. No puedo usar readlines() ya que crea una lista muy grande en la memoria.

  • Si necesita manejar un binario archivo, consulte ¿Cuál es la forma idiomática de iterar sobre un archivo binario?

    – Karl Knechtel

    9 de agosto a las 1:34

avatar de usuario
Juan La Rooy

Utilizar una for bucle en un objeto de archivo para leerlo línea por línea. Usar with open(...) dejar un administrador de contexto asegúrese de que el archivo esté cerrado después de leer:

with open("log.txt") as infile:
    for line in infile:
        print(line)

  • la pregunta sigue siendo, “para la línea en el archivo” ¿cargará mis 5 GB de líneas en la memoria? y, ¿Cómo puedo leer desde la cola?

    – Bruno Rocha – rochacbruno

    25 de junio de 2011 a las 2:31

  • @rochacbruno, solo lee una línea a la vez. Cuando se lea la siguiente línea, la anterior se recolectará como basura a menos que haya almacenado una referencia a ella en otro lugar

    – John LaRooy

    25 de junio de 2011 a las 2:33

  • @rochacbruno, Desafortunadamente, leer las líneas en orden inverso no es tan fácil de hacer de manera eficiente. En general, querrá leer desde el final del archivo en fragmentos de tamaño razonable (de kilobytes a megabytes, por ejemplo) y dividirlos en caracteres de nueva línea (o cualquiera que sea el carácter de final de línea en su plataforma)

    – John LaRooy

    25 de junio de 2011 a las 2:36

  • ¡Gracias! Encontré la solución de cola stackoverflow.com/questions/5896079/…

    – Bruno Rocha – rochacbruno

    25 de junio de 2011 a las 3:09

  • @bawejakunal, ¿quieres decir si una línea es demasiado larga para cargarla en la memoria de una vez? Eso es inusual para un texto expediente. En lugar de usar for bucle que itera sobre las líneas, puede usar chunk = infile.read(chunksize) para leer fragmentos de tamaño limitado independientemente de su contenido. Tendrás que buscar dentro de los fragmentos las nuevas líneas tú mismo.

    – John LaRooy

    09/01/2018 a las 21:50

avatar de usuario
keith

Todo lo que necesita hacer es usar el objeto de archivo como un iterador.

for line in open("log.txt"):
    do_something_with(line)

Aún mejor es usar el administrador de contexto en versiones recientes de Python.

with open("log.txt") as fileobject:
    for line in fileobject:
        do_something_with(line)

Esto también cerrará automáticamente el archivo.

  • ¿Eso no es cargar todo el archivo en la memoria?

    – Bruno Rocha – rochacbruno

    25 de junio de 2011 a las 2:10

  • ¿No debería cerrar el archivo después del ciclo en el primer ejemplo?

    – maciejwww

    9 de junio de 2021 a las 10:13

  • @maciejwww sí, pero no lo hice para que se pareciera más al ejemplo OP. El segundo ejemplo utiliza el with declaración es un “administrador de contexto” que cierra automáticamente el objeto de archivo.

    – Keith

    10 de junio de 2021 a las 6:07


Un enfoque de la vieja escuela:

fh = open(file_name, 'rt')
line = fh.readline()
while line:
    # do stuff with line
    line = fh.readline()
fh.close()

  • comentario menor: para la seguridad de excepción, se recomienda usar la instrucción ‘with’, en su caso, “with open(filename, ‘rt’) as fh:”

    – prokher

    15 de enero de 2015 a las 14:44

  • @prokher: Sí, pero lo llamé “vieja escuela”.

    – PTBNL

    16 de enero de 2015 a las 13:40

avatar de usuario
jyoti das

Por favor, intente esto:

with open('filename','r',buffering=100000) as f:
    for line in f:
        print line

avatar de usuario
Mikola

Es mejor usar un iterador en su lugar.
Importante: fileinput — Iterar sobre líneas de múltiples flujos de entrada.

De los documentos:

import fileinput
for line in fileinput.input("filename", encoding="utf-8"):
    process(line)

Esto evitará copiar todo el archivo en la memoria a la vez.

  • Aunque los documentos muestran el fragmento como “uso típico”, usarlo no llama al close() método de la devolución FileInput objeto de clase cuando finaliza el ciclo, por lo que evitaría usarlo de esta manera. En Python 3.2 finalmente han hecho fileinput compatible con el protocolo del administrador de contexto que aborda este problema (pero el código aún no se escribiría de la manera que se muestra).

    – martineau

    24 de julio de 2012 a las 3:50

avatar de usuario
sivan

Esto es lo que debe hacer si no tiene líneas nuevas en el archivo:

with open('large_text.txt') as f:
  while True:
    c = f.read(1024)
    if not c:
      break
    print(c,end='')

  • Aunque los documentos muestran el fragmento como “uso típico”, usarlo no llama al close() método de la devolución FileInput objeto de clase cuando finaliza el ciclo, por lo que evitaría usarlo de esta manera. En Python 3.2 finalmente han hecho fileinput compatible con el protocolo del administrador de contexto que aborda este problema (pero el código aún no se escribiría de la manera que se muestra).

    – martineau

    24 de julio de 2012 a las 3:50

No podía creer que pudiera ser tan fácil como parecía la respuesta de @john-la-rooy. Entonces, recreé el cp comando utilizando la lectura y escritura línea por línea. Es LOCO RÁPIDO.

#!/usr/bin/env python3.6

import sys

with open(sys.argv[2], 'w') as outfile:
    with open(sys.argv[1]) as infile:
        for line in infile:
            outfile.write(line)

  • NOTA: Debido a que python readline estandariza los finales de línea, esto tiene el efecto secundario de convertir documentos con finales de línea de DOS de \r\n a los finales de línea de Unix de \n. Toda mi razón para buscar este tema fue que necesitaba convertir un archivo de registro que recibe un revoltijo de finales de línea (porque el desarrollador usó ciegamente varias bibliotecas .NET). Me sorprendió descubrir que después de mi prueba de velocidad inicial, no necesitaba volver atrás y rstrip las líneas. ¡Ya estaba perfecto!

    –Bruno Bronosky

    11 de agosto de 2017 a las 13:13

¿Ha sido útil esta solución?