Question

J'ai un très gros fichier de 4 Go et lorsque je tente de lire mon ordinateur se bloque. Je tiens donc à le lire morceau par morceau et après le traitement de chaque pièce stocker la pièce traitée dans un autre fichier et lire morceau suivant.

est-il une méthode pour ces pièces yield?

J'aimerais avoir une méthode paresseuse .

Était-ce utile?

La solution

Pour écrire une fonction paresseux, il suffit d'utiliser 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)

Une autre option serait d'utiliser et iter une fonction d'assistance:

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

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

Si le fichier est basé en ligne, l'objet de fichier est déjà un générateur paresseux de lignes:

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

Autres conseils

Si votre ordinateur, système d'exploitation et python sont 64 bits , vous pouvez utiliser le module mMAP pour carte le contenu du fichier dans la mémoire et l'accès avec des indices et des tranches. Voici un exemple de la documentation:

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 l'ordinateur, OS ou python sont 32 bits , puis mmap-ing de gros fichiers peuvent réserver une grande partie de l'espace d'adressage et mourir de faim votre programme de mémoire.

file.readlines () prend dans un argument de taille en option qui se rapproche du nombre de lignes lu dans les lignes retourné.

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)

Il y a déjà beaucoup de bonnes réponses, mais je suis tombé sur un problème similaire récemment et la solution que je avais besoin ne figure pas ici, donc je pensais que je pouvais compléter ce fil.

80% du temps, je dois lire des fichiers ligne par ligne. Ensuite, comme l'a suggéré dans cette répondre , vous voulez utiliser l'objet fichier lui-même comme générateur paresseux:

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

Cependant, j'ai récemment rencontré un très très grand (presque) csv ligne unique, où le séparateur de rangée était en fait pas, mais '\n' '|'.

  • ligne de lecture par la ligne n'a pas été une option, mais je reste nécessaire pour traiter ligne par ligne.
  • Conversion à <=> avant le traitement était <=> également de la question, parce que certains des champs de cette csv contenu <=> (entrée utilisateur de texte libre).
  • Utilisation de la bibliothèque csv a également été exclu parce que le fait que, au moins dans les premières versions du lib, il est codé en dur à lire la ligne d'entrée par ligne .

Je suis venu avec l'extrait suivant:

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

Je l'ai testé avec succès sur de gros fichiers et bloc de taille différentes (j'ai même essayé un chunksize de 1 octet, juste pour vérifier que l'algorithme n'est pas fonction de la taille).

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

Mise à jour: L'approche est mieux expliqué dans https://stackoverflow.com/a/4566523/38592

Je ne suis pas autorisé à commenter en raison de ma faible réputation, mais la solution de SilentGhosts devrait être beaucoup plus facile avec file.readlines ([sizeHint])

méthodes de fichier python

edit: SilentGhost est juste, mais cela devrait être mieux que:

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

Je pense que nous pouvons écrire comme ceci:

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)

Je suis dans une situation un peu similaire. On ne sait pas si vous connaissez la taille du morceau en octets; Je ne sont généralement pas, mais le nombre d'enregistrements (lignes) qui est nécessaire est connu:

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

Mise à jour : Merci nosklo. Voici ce que je voulais dire. Il fonctionne presque, sauf qu'il perd une ligne « entre » morceaux.

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

Est-ce que l'affaire w / o perdre toutes les lignes, mais il ne semble pas très agréable.

Reportez-vous à la documentation officielle de python https: // docs .python.org / zh-cn / 3 / bibliothèque / functions.html? NB_ITER

Peut-être que cette méthode est plus pythonique:

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)

à la ligne de processus en ligne, ceci est une solution élégante:

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

Tant qu'il n'y a pas de lignes vides sommes.

vous pouvez utiliser le code suivant.

file_obj = open('big_file') 

open () retourne un objet de fichier

utilisez os.stat pour obtenir la taille

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

for i in range( file_size/1024):
    print file_obj.read(1024)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top