Yo tengo un gran archivo de 4GB y cuando trato de leer mi equipo se bloquea.
Así que quiero leer pieza por pieza y después de la elaboración de cada pieza de la tienda el procesado de la pieza en otro archivo y leer la próxima pieza.

¿Hay algún método para yield estas piezas ?

Me encantaría tener un método de lazy.

11 Comentarios

  1. 370

    Para escribir un perezoso función, sólo tiene que utilizar rendimiento:

    def read_in_chunks(file_object, chunk_size=1024):
        """Lazy function (generator) to read a file piece by piece.
        Default chunk size: 1k."""
        while True:
            data = file_object.read(chunk_size)
            if not data:
                break
            yield data
    
    
    f = open('really_big_file.dat')
    for piece in read_in_chunks(f):
        process_data(piece)

    Otra opción sería el uso de iter y una función auxiliar:

    f = open('really_big_file.dat')
    def read1k():
        return f.read(1024)
    
    for piece in iter(read1k, ''):
        process_data(piece)

    Si el archivo está basado en la línea, al objeto de archivo que ya es un perezoso generador de líneas:

    for line in open('really_big_file.dat'):
        process_data(line)
    • Por lo que la línea f = open('really_big_file.dat') es simplemente un puntero sin ningún consumo de memoria? (Me refiero a la memoria consumida es la misma sin importar el tamaño del archivo?) Cómo va a afectar al rendimiento si puedo usar urllib.readline() en lugar de f.readline()?
    • Una buena práctica utilizar open(‘really_big_file.dat’, ‘rb’) para la compatibilidad con nuestro Posix-desafió Windows con los colegas.
    • para hacer aún más corto, uso functools.partial.
    • Como esta pregunta fue respondida en el ’09 yo tenía una pregunta de seguimiento en este. Es el método de la lectura de las líneas de un archivo de gran tamaño utilizando file_handle.readline() es más eficiente que este? (Python 2.7)
    • no, la iteración es un poco más eficiente, ya que se almacena en caché un poco más en python 2.7;
    • U significa la readline() es mejor? Gracias por la respuesta
    • los búferes de menos datos. Si eso es una buena cosa o no es otro asunto, que depende del problema. Cuando la lectura de un descriptor de archivo conectado a otro proceso, tal vez puede ser mejor, así que usted puede conseguir los resultados que aparecen en el tubo (no búfer). Por otro lado, el almacenamiento en búfer da más rendimiento si vas a procesar todos los datos de todos modos. Es una cuestión de equilibrio.
    • Falta rb como @Tal Weiss mencionados; y la falta de un file.close() declaración (podría utilizar with open('really_big_file.dat', 'rb') as f: para lograr el mismo; Ver aquí por otro concisa de la aplicación
    • Corrió en una cuestión en la que yo estaba escribiendo en un archivo de registro en el archivo de lectura de bucle, como tal cuando me lea el archivo de registro que nunca terminó de leer.
    • texto y archivos binarios son cosas diferentes. Ambos tipos son útiles, pero en diferentes casos. El valor predeterminado () texto modo puede ser útil aquí, es decir, 'rb' es no que faltan.
    • cierto, el OP no se especifica si fue la lectura de texto o datos binarios. Pero si él está usando python 2.7 en Windows y es lectura de datos binarios, es sin duda vale la pena señalar que si se olvida de la 'b' sus datos se es muy probable que sea dañado. a partir De la documentaciónPython on Windows makes a distinction between text and binary files; [...] it’ll corrupt binary data like that in JPEG or EXE files. Be very careful to use binary mode when reading and writing such files.
    • Podemos usar este método para cargar grandes extensiones de archivo a través de UDP a un servidor remoto?
    • Cómo el método read_in_chunks() sabrá que ha llegado al final del archivo?
    • Una vez que se ha producido, el control vuelve a la línea de data = file_object.read(chunk_size), ¿no es leer la misma cantidad de nuevo?
    • He aquí un generador que devuelve 1k fragmentos: buf_iter = (x for x in iter(lambda: buf.read(1024), '')). Luego for chunk in buf_iter: un bucle a través de los trozos.
    • su generador de comprensión es inútil, se puede utilizar sólo for chunk in iter(lambda: buf.read(1024), '')): directamente
    • Hmm, ya veo, gracias por la sugerencia.
    • eh, leer la respuesta completa? Ya hay un método para que la lista!
    • oh, sí! disculpas, y gracias!
    • Si estoy leyendo un archivo de texto en fragmentos… ¿cómo puedo asegurarme de que mi gordi no terminan de dividir una palabra en pedazos? Quiero que el fragmento se rompe a suceder en el espacio en blanco o algún otro delimitador (básicamente no ASCII letra)
    • usted puede utilizar yield para escribir una función que lee un fragmento y se divide en palabras, y, a continuación, yield cada palabra por separado. Usted puede, a continuación, guarde el dividir la pieza de la palabra en un búfer variable, para unirse con el siguiente fragmento de la iteración. Todo depende de lo que el código necesita.
    • sería este enfoque de trabajo con jerárquica estructurada de datos JSON que contiene la lista de registros, pero en el que cada registro no está orientada a líneas, y abarca múltiples (posiblemente diferente) clave-valor JSON estructuras.

  2. 34

    Si su ordenador, el sistema operativo y python son de 64 bits, entonces usted puede utilizar el módulo mmap para asignar el contenido del archivo en la memoria y acceder a ella con índices y sectores. Aquí un ejemplo de la documentación:

    import mmap
    with open("hello.txt", "r+") as f:
        # memory-map the file, size 0 means whole file
        map = mmap.mmap(f.fileno(), 0)
        # read content via standard file methods
        print map.readline()  # prints "Hello Python!"
        # read content via slice notation
        print map[:5]  # prints "Hello"
        # update content using slice notation;
        # note that new content must have same size
        map[6:] = " world!\n"
        # ... and read again using standard file methods
        map.seek(0)
        print map.readline()  # prints "Hello  world!"
        # close the map
        map.close()

    Si su ordenador, el sistema operativo o python son de 32 bits, a continuación, mmap-ing archivos de gran tamaño puede reservar gran parte de su espacio de direcciones y de hambre su programa de la memoria.

    • Esto no funciona, consulte esta pregunta
    • Cómo es esto supone trabajar? Lo que si tengo una de 32 gb archivo? Lo que si estoy en una VM con 256 mb de RAM? Mmapping un archivo tan grande es realmente una buena cosa nunca.
    • Esta respuesta se merecen un -12 voto . Esto matará cualquier persona el uso que para archivos de gran tamaño.
    • Esto puede funcionar en 64 bits Python incluso para archivos de gran tamaño. Incluso aunque el archivo asignado en memoria, no se de lectura a la memoria, por lo que la cantidad de memoria física puede ser mucho más pequeño que el tamaño del archivo.
    • ¿el tamaño de la memoria física de la materia con mmaping un archivo?
    • He tratado de mmap 32 GB de archivos de 64 bits de Python. funciona (tengo menos RAM de 32 gb): puedo acceder al inicio, en medio y al final del archivo usando tanto la Secuencia y el archivo de interfaces.

  3. 27

    archivo.readlines() toma un tamaño opcional argumento de que se aproxima el número de líneas leídas en las líneas devueltas.

    bigfile = open('bigfilename','r')
    tmp_lines = bigfile.readlines(BUF_SIZE)
    while tmp_lines:
        process([line for line in tmp_lines])
        tmp_lines = bigfile.readlines(BUF_SIZE)
    • es realmente una gran idea, especialmente cuando es combinado con el defaultdict para dividir grandes de datos en los más pequeños.
    • Yo recomendaría usar .read() no .readlines(). Si el archivo es binario no va a tener saltos de línea.
  4. 20

    Ya hay muchas buenas respuestas, pero me encontré con un problema similar hace poco y la solución que necesita no está en la lista, así que pensé que podría complementar este hilo.

    El 80% del tiempo, necesito leer archivos línea por línea. Entonces, como se sugiere en este respuesta, desea utilizar el archivo de objeto en sí mismo como perezoso generador:

    with open('big.csv') as f:
        for line in f:
            process(line)

    Sin embargo, hace poco me encontré con una muy, muy grande (casi) única línea csv, donde el separador de filas de hecho no era '\n' pero '|'.

    • Lectura línea por línea no era una opción, pero todavía me faltaba proceso de fila por fila.
    • La conversión de'|' a '\n' antes de procesar también estaba fuera de la cuestión, debido a que algunos de los campos de este formato csv contenida '\n' (texto libre entrada de usuario).
    • Utilizando el csv de la biblioteca también fue descartado porque el hecho de que, al menos en las primeras versiones de la lib, es codificado para leer la línea de entrada de la línea de.

    Me encontré con el siguiente fragmento de código:

    def rows(f, chunksize=1024, sep='|'):
        """
        Read a file where the row separator is '|' lazily.
    
        Usage:
    
        >>> with open('big.csv') as f:
        >>>     for r in rows(f):
        >>>         process(row)
        """
        incomplete_row = None
        while True:
            chunk = f.read(chunksize)
            if not chunk: # End of file
                if incomplete_row is not None:
                    yield incomplete_row
                    break
            # Split the chunk as long as possible
            while True:
                i = chunk.find(sep)
                if i == -1:
                    break
                # If there is an incomplete row waiting to be yielded,
                # prepend it and set it back to None
                if incomplete_row is not None:
                    yield incomplete_row + chunk[:i]
                    incomplete_row = None
                else:
                    yield chunk[:i]
                chunk = chunk[i+1:]
            # If the chunk contained no separator, it needs to be appended to
            # the current incomplete row.
            if incomplete_row is not None:
                incomplete_row += chunk
            else:
                incomplete_row = chunk

    Lo he probado con éxito en archivos de gran tamaño y con diferentes tamaños de fragmento (incluso he intentado una chunksize de 1 byte, sólo para asegurarse de que el algoritmo no depende del tamaño).

  5. 9
    f = ... # file-like object, i.e. supporting read(size) function and 
            # returning empty string '' when there is nothing to read
    
    def chunked(file, chunk_size):
        return iter(lambda: file.read(chunk_size), '')
    
    for data in chunked(f, 65536):
        # process the data

    ACTUALIZACIÓN: El enfoque que se explica mejor en https://stackoverflow.com/a/4566523/38592

    • Esto funciona bien para los blobs, pero no puede ser bueno para la línea separados de contenido (como CSV, HTML, etc, donde el procesamiento debe ser manejado línea por línea)
  6. 2

    Yo creo que se puede escribir así:

    def read_file(path, block_size=1024): 
        with open(path, 'rb') as f: 
            while True: 
                piece = f.read(block_size) 
                if piece: 
                    yield piece 
                else: 
                    return
    
    for piece in read_file(path):
        process_piece(piece)
  7. 1

    no se me permite el comentario, debido a mi baja reputación, pero SilentGhosts solución debería ser mucho más fácil con el archivo.readlines([sizehint])

    archivo de python métodos

    edición: SilentGhost es correcto, pero esto debe ser mejor que:

    s = "" 
    for i in xrange(100): 
       s += file.next()
    • sizehint es en bytes
    • ok, lo siento, tienes toda la razón. pero tal vez esta solución va a hacer más feliz 😉 : s = «» for i in xrange(100): s += archivo.next()
    • -1: Terrible solución, esto significaría la creación de una nueva cadena en la memoria de cada línea, y copiar todo el archivo de lectura de datos a la nueva cadena. La peor actuación y la memoria.
    • ¿por qué iba a copiar todo el archivo de datos en una nueva cadena? a partir de la documentación de python: con el fin De hacer un bucle for, de la manera más eficiente de bucle a través de las líneas de un archivo (una operación muy común), el método next() utiliza un oculto de la lectura anticipada de búfer.
    • o concatenación de cadenas, se hace una nueva copia de la cadena en cada momento, ya que la cadena es inmutable, por lo que están creando una nueva cadena.
    • estos son los detalles de la implementación, la comprensión de listas pueden ser usados en su lugar

  8. 1

    Estoy en algo similar situación. No está claro si sabes el pedazo tamaño en bytes; por lo general no, pero el número de registros (líneas) que se requiere es conocido:

    def get_line():
         with open('4gb_file') as file:
             for i in file:
                 yield i
    
    lines_required = 100
    gen = get_line()
    chunk = [i for i, j in zip(gen, range(lines_required))]

    Actualización: Gracias nosklo. Aquí a lo que me refería. Casi obras, salvo que se pierde una línea de ‘entre’ cachos.

    chunk = [next(gen) for i in range(lines_required)]

    Hace el truco w/o perder ninguna de las líneas, pero no tiene un aspecto muy agradable.

    • es esta pseudo código? no va a funcionar. También es innecesario confuso, usted debe hacer que el número de líneas de un parámetro opcional para el get_line función.
  9. 1

    Se refieren a python de la documentación oficial https://docs.python.org/zh-cn/3/library/functions.html?#iter

    Tal vez este método es más python:

    from functools import partial
    
    """A file object returned by open() is a iterator with
    read method which could specify current read's block size"""
    with open('mydata.db', 'r') as f_in:
    
        part_read = partial(f_in.read, 1024*1024)
        iterator = iter(part_read, b'')
    
        for index, block in enumerate(iterator, start=1):
            block = process_block(block)    # process block data
            with open(f'{index}.txt', 'w') as f_out:
                f_out.write(block)
  10. 0

    A proceso, línea por línea, esta es una solución elegante:

      def stream_lines(file_name):
        file = open(file_name)
        while True:
          line = file.readline()
          if not line:
            file.close()
            break
          yield line

    Mientras no hay líneas en blanco.

    • Esto es sólo un poco complicado, menos robusto, y más lento equivalente a lo que open ya le da. Un archivo es ya un iterador a través de sus líneas.
  11. -1

    puede utilizar el siguiente código.

    file_obj = open('big_file') 

    open() devuelve un objeto de archivo

    a continuación, utilizar os.stat para obtener el tamaño de la

    file_size = os.stat('big_file').st_size
    
    for i in range( file_size/1024):
        print file_obj.read(1024)
    • no leer todo el archivo si el tamaño no es una multiplicar de 1024

Dejar respuesta

Please enter your comment!
Please enter your name here