Lire un fichier dans l'ordre inverse en utilisant python

Comment lire un fichier dans l'ordre inverse en utilisant python? Je veux lire un fichier de la dernière ligne à la première.

89
demandé sur Nick Volynkin 2010-02-20 13:09:26

15 réponses

for line in reversed(open("filename").readlines()):
    print line.rstrip()

et en Python 3:

for line in reversed(list(open("filename"))):
    print(line.rstrip())
59
répondu Matt Joiner 2013-03-07 03:24:21

Une bonne, réponse efficace à l'écrit comme un générateur.

import os

def reverse_readline(filename, buf_size=8192):
    """a generator that returns the lines of a file in reverse order"""
    with open(filename) as fh:
        segment = None
        offset = 0
        fh.seek(0, os.SEEK_END)
        file_size = remaining_size = fh.tell()
        while remaining_size > 0:
            offset = min(file_size, offset + buf_size)
            fh.seek(file_size - offset)
            buffer = fh.read(min(remaining_size, buf_size))
            remaining_size -= buf_size
            lines = buffer.split('\n')
            # the first line of the buffer is probably not a complete line so
            # we'll save it and append it to the last line of the next buffer
            # we read
            if segment is not None:
                # if the previous chunk starts right from the beginning of line
                # do not concact the segment to the last line of new chunk
                # instead, yield the segment first 
                if buffer[-1] is not '\n':
                    lines[-1] += segment
                else:
                    yield segment
            segment = lines[0]
            for index in range(len(lines) - 1, 0, -1):
                if len(lines[index]):
                    yield lines[index]
        # Don't yield None if the file was empty
        if segment is not None:
            yield segment
100
répondu srohde 2016-05-17 08:35:08

Que Diriez-vous de quelque chose comme ceci:

import os


def readlines_reverse(filename):
    with open(filename) as qfile:
        qfile.seek(0, os.SEEK_END)
        position = qfile.tell()
        line = ''
        while position >= 0:
            qfile.seek(position)
            next_char = qfile.read(1)
            if next_char == "\n":
                yield line[::-1]
                line = ''
            else:
                line += next_char
            position -= 1
        yield line[::-1]


if __name__ == '__main__':
    for qline in readlines_reverse(raw_input()):
        print qline

Depuis le fichier est en lecture caractère par caractère dans l'ordre inverse, il fonctionnera même sur de très gros fichiers, tant que les lignes individuelles tenir en mémoire.

16
répondu Berislav Lopac 2014-11-05 01:09:22

vous pouvez également utiliser le module python file_read_backwards .

après l'installation, via pip install file_read_backwards (v1.2.1), vous pouvez lire le dossier entier à l'envers (ligne-wise) d'une manière efficace de la mémoire via:

#!/usr/bin/env python2.7

from file_read_backwards import FileReadBackwards

with FileReadBackwards("/path/to/file", encoding="utf-8") as frb:
    for l in frb:
         print l

il supporte les encodages"utf-8"," latin-1", et" ascii".

est également disponible pour python3. D'autres documents peuvent être trouvés à http://file-read-backwards.readthedocs.io/en/latest/readme.html

9
répondu user7321751 2018-03-28 02:06:47
for line in reversed(open("file").readlines()):
    print line.rstrip()

si vous êtes sous linux, vous pouvez utiliser la commande tac .

$ tac file

2 recettes que vous pouvez trouver dans ActiveState ici et ici

8
répondu ghostdog74 2010-02-20 11:11:00
import re

def filerev(somefile, buffer=0x20000):
  somefile.seek(0, os.SEEK_END)
  size = somefile.tell()
  lines = ['']
  rem = size % buffer
  pos = max(0, (size // buffer - 1) * buffer)
  while pos >= 0:
    somefile.seek(pos, os.SEEK_SET)
    data = somefile.read(rem + buffer) + lines[0]
    rem = 0
    lines = re.findall('[^\n]*\n?', data)
    ix = len(lines) - 2
    while ix > 0:
      yield lines[ix]
      ix -= 1
    pos -= buffer
  else:
    yield lines[0]

with open(sys.argv[1], 'r') as f:
  for line in filerev(f):
    sys.stdout.write(line)
8
répondu Ignacio Vazquez-Abrams 2013-05-07 02:20:59

ici vous pouvez trouver mon implémentation my, vous pouvez limiter l'utilisation de la ram en changeant la variable" buffer", il y a un bug que le programme affiche une ligne vide au début.

et aussi l'utilisation de la ram peut être augmentée s'il n'y a pas de nouvelles lignes pour plus que des octets tampons, la variable" leak "va augmenter jusqu'à voir une nouvelle ligne ("\n").

cela fonctionne aussi pour les fichiers de 16 Go qui sont plus gros que ma mémoire totale.

import os,sys
buffer = 1024*1024 # 1MB
f = open(sys.argv[1])
f.seek(0, os.SEEK_END)
filesize = f.tell()

division, remainder = divmod(filesize, buffer)
line_leak=''

for chunk_counter in range(1,division + 2):
    if division - chunk_counter < 0:
        f.seek(0, os.SEEK_SET)
        chunk = f.read(remainder)
    elif division - chunk_counter >= 0:
        f.seek(-(buffer*chunk_counter), os.SEEK_END)
        chunk = f.read(buffer)

    chunk_lines_reversed = list(reversed(chunk.split('\n')))
    if line_leak: # add line_leak from previous chunk to beginning
        chunk_lines_reversed[0] += line_leak

    # after reversed, save the leakedline for next chunk iteration
    line_leak = chunk_lines_reversed.pop()

    if chunk_lines_reversed:
        print "\n".join(chunk_lines_reversed)
    # print the last leaked line
    if division - chunk_counter < 0:
        print line_leak
2
répondu Bekir Dogan 2013-02-27 18:01:17

Merci pour la réponse @srohde. Il a une petite vérification de bogue pour le caractère newline Avec " is " opérateur, et je ne pouvais pas commenter la réponse avec 1 réputation. Aussi, je voudrais gérer le fichier ouvert à l'extérieur parce que cela me permet d'intégrer mes divagations pour les tâches luigi.

ce que j'avais besoin de changer a la forme:

with open(filename) as fp:
    for line in fp:
        #print line,  # contains new line
        print '>{}<'.format(line)

j'aimerais changer pour:

with open(filename) as fp:
    for line in reversed_fp_iter(fp, 4):
        #print line,  # contains new line
        print '>{}<'.format(line)

Voici une réponse modifiée qui veut un fichier poignée et garde des retours à la ligne:

def reversed_fp_iter(fp, buf_size=8192):
    """a generator that returns the lines of a file in reverse order
    ref: https://stackoverflow.com/a/23646049/8776239
    """
    segment = None  # holds possible incomplete segment at the beginning of the buffer
    offset = 0
    fp.seek(0, os.SEEK_END)
    file_size = remaining_size = fp.tell()
    while remaining_size > 0:
        offset = min(file_size, offset + buf_size)
        fp.seek(file_size - offset)
        buffer = fp.read(min(remaining_size, buf_size))
        remaining_size -= buf_size
        lines = buffer.splitlines(True)
        # the first line of the buffer is probably not a complete line so
        # we'll save it and append it to the last line of the next buffer
        # we read
        if segment is not None:
            # if the previous chunk starts right from the beginning of line
            # do not concat the segment to the last line of new chunk
            # instead, yield the segment first
            if buffer[-1] == '\n':
                #print 'buffer ends with newline'
                yield segment
            else:
                lines[-1] += segment
                #print 'enlarged last line to >{}<, len {}'.format(lines[-1], len(lines))
        segment = lines[0]
        for index in range(len(lines) - 1, 0, -1):
            if len(lines[index]):
                yield lines[index]
    # Don't yield None if the file was empty
    if segment is not None:
        yield segment
2
répondu Murat Yükselen 2017-10-14 15:18:16

une fonction simple pour créer un second fichier inversé (linux seulement):

import os
def tac(file1, file2):
     print(os.system('tac %s > %s' % (file1,file2)))

comment utiliser

tac('ordered.csv', 'reversed.csv')
f = open('reversed.csv')
2
répondu Alexandre Andrade 2018-02-07 05:24:25

si vous êtes préoccupé par la taille du fichier / l'utilisation de la mémoire, la cartographie de la mémoire du fichier et la recherche de nouvelles lignes à l'envers est une solution:

Comment rechercher une chaîne de caractères dans des fichiers texte?

1
répondu Federico 2018-02-08 10:29:46
def reverse_lines(filename):
    y=open(filename).readlines()
    return y[::-1]
0
répondu Gareema 2015-11-13 05:32:01

toujours utiliser with quand vous travaillez avec des fichiers car il gère tout pour vous:

with open('filename', 'r') as f:
    for line in reversed(f.readlines()):
        print line

ou en Python 3:

with open('filename', 'r') as f:
    for line in reversed(list(f.readlines())):
        print(line)
0
répondu Carlos Afonso 2016-08-02 15:19:59

vous devez d'abord ouvrir votre fichier en format read, le sauvegarder sur une variable, puis ouvrir le second fichier en format write où vous écririez ou ajouteriez la variable en utilisant un [: -1] slice, inversant complètement le fichier. Vous pouvez également utiliser readlines() pour faire une liste de lignes, vous pouvez manipuler

def copy_and_reverse(filename, newfile):
    with open(filename) as file:
        text = file.read()
    with open(newfile, "w") as file2:
        file2.write(text[::-1])
0
répondu PawlakJ 2018-06-07 12:47:47

la plupart des réponses doivent lire le dossier complet avant de faire quoi que ce soit. Cet échantillon contient des échantillons de plus en plus grands à partir de la fin .

J'ai seulement vu la réponse de Murat Yükselen en écrivant cette réponse. C'est presque le même, qui, je suppose, est une bonne chose. L'exemple ci-dessous traite aussi avec \r et augmente sa taille de tampon à chaque étape. J'ai aussi quelques tests unitaires pour sauvegarder ce code.

def readlines_reversed(f):
    """ Iterate over the lines in a file in reverse. The file must be
    open in 'rb' mode. Yields the lines unencoded (as bytes), including the
    newline character. Produces the same result as readlines, but reversed.
    If this is used to reverse the line in a file twice, the result is
    exactly the same.
    """
    head = b""
    f.seek(0, 2)
    t = f.tell()
    buffersize, maxbuffersize = 64, 4096
    while True:
        if t <= 0:
            break
        # Read next block
        buffersize = min(buffersize * 2, maxbuffersize)
        tprev = t
        t = max(0, t - buffersize)
        f.seek(t)
        lines = f.read(tprev - t).splitlines(True)
        # Align to line breaks
        if not lines[-1].endswith((b"\n", b"\r")):
            lines[-1] += head  # current tail is previous head
        elif head == b"\n" and lines[-1].endswith(b"\r"):
            lines[-1] += head  # Keep \r\n together
        elif head:
            lines.append(head)
        head = lines.pop(0)  # can be '\n' (ok)
        # Iterate over current block in reverse
        for line in reversed(lines):
            yield line
    if head:
        yield head
0
répondu Almar 2018-09-10 21:35:22

j'ai dû le faire il y a quelques temps et utilisé le code ci-dessous. Il des tuyaux pour le shell. Je crains de ne plus avoir le script complet. Si vous êtes sur un système d'exploitation unixish, vous pouvez utiliser "tac", cependant sur par exemple Mac OSX tac commande ne fonctionne pas, utilisez tail-R. L'extrait de code ci-dessous teste sur quelle plate-forme vous êtes, et ajuste la commande en conséquence

# We need a command to reverse the line order of the file. On Linux this
# is 'tac', on OSX it is 'tail -r'
# 'tac' is not supported on osx, 'tail -r' is not supported on linux.

if sys.platform == "darwin":
    command += "|tail -r"
elif sys.platform == "linux2":
    command += "|tac"
else:
    raise EnvironmentError('Platform %s not supported' % sys.platform)
-2
répondu jeorgen 2011-12-07 23:20:03