Frage

Ich habe eine sehr große Datei 4 GB und wenn ich versuche, es meinen Computer hängt zu lesen. Deshalb mag ich es Stück für Stück lesen und nach der Verarbeitung jedes Stück speichert das verarbeitete Stück in einer anderen Datei und nächstes Stück lesen.

Gibt es eine Methode, um diese Stücke zu yield?

Ich würde gerne eine faul Methode haben .

War es hilfreich?

Lösung

eine faule Funktion zu schreiben, benutzen Sie einfach yield :

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)

Eine weitere Option wäre verwenden iter und eine Hilfsfunktion:

f = open('really_big_file.dat')
def read1k():
    return f.read(1024)

for piece in iter(read1k, ''):
    process_data(piece)

Wenn die Datei zeilenbasiert, das Dateiobjekt ist bereits ein fauler Generator von Zeilen:

for line in open('really_big_file.dat'):
    process_data(line)

Andere Tipps

Wenn der Computer, Betriebssystem und Python 64-Bit ist, dann können Sie die mmap Modul den Inhalt der Datei in den Speicher und greifen sie mit Indizes und Scheiben abzubilden. Hier ein Beispiel aus der Dokumentation:

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

Wenn entweder Ihren Computer, Betriebssystem oder Python sind 32-Bit , dann mmap-ing große Dateien können große Teile des Adressraums und verhungern Ihr Programm Speicher.

file.readlines () nimmt in einem optionalen Größe Argumente, das die Anzahl der Zeilen in den Zeilen lesen annähert zurückgegeben.

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 gibt bereits viele gute Antworten, aber ich lief in ein ähnliches Problem vor kurzem, und die Lösung, die ich benötigt ist hier nicht aufgeführt, so dass ich dachte ich diesen Thread ergänzen könnte.

80% der Zeit, ich brauche Dateien Zeile für Zeile zu lesen. Dann href="https://stackoverflow.com/a/519653/628786"> wie in diesem , Sie wollen Objekt die Datei verwenden, selbst als faul Generator:

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

Allerdings habe ich vor kurzem lief in eine sehr, sehr groß (fast) einzige Zeile csv, wo die Zeilentrenn war in der Tat nicht '\n' aber '|'.

Ich kam mit dem folgenden Ausschnitt oben:

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

ich es auf große Dateien und mit unterschiedlichen Blockgrößen erfolgreich getestet habe (ich habe sogar versucht, eine chunksize von 1 Byte, nur um sicherzustellen, dass der Algorithmus ist nicht größenabhängig).

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

UPDATE: Der Ansatz ist am besten erklärt in https://stackoverflow.com/a/4566523/38592

ich darf nicht aufgrund meiner geringen Ruf kommentieren, aber SilentGhosts Lösung sollte viel einfacher, mit file.readlines ([sizeHint])

sein

Python-Datei Methoden

edit: SilentGhost ist richtig, aber dies sollte besser sein als:

s = "" 
for i in xrange(100): 
   s += file.next()

Ich denke, wir können so schreiben:

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)

Ich bin in einer ähnlichen Situation. Es ist nicht klar, ob Sie Chunkgröße in Bytes kennen; Normalerweise mache ich nicht, aber die Anzahl der Datensätze (Zeilen), die erforderlich ist, ist bekannt:

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

Aktualisieren : Danke nosklo. Hier ist, was ich meinte. Es funktioniert fast, mit der Ausnahme, dass es eine Linie ‚zwischen‘ Chunks verliert.

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

funktioniert der Trick w / o alle Zeilen zu verlieren, aber es sieht nicht sehr schön.

Siehe offizielle Dokumentation https: // docs .python.org / zh-cn / 3 / library / functions.html? #iter

Vielleicht ist diese Methode pythonic:

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)

Um die Prozess Zeile für Zeile, ist dies eine elegante Lösung:

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

Solange es keine Leerzeilen sind.

können Sie folgenden Code verwenden.

file_obj = open('big_file') 

open () gibt ein Dateiobjekt

dann verwenden os.stat für immer Größe

file_size = os.stat('big_file').st_size

for i in range( file_size/1024):
    print file_obj.read(1024)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top