How to read a file in reverse order?

前端 未结 21 2515
礼貌的吻别
礼貌的吻别 2020-11-22 04:51

How to read a file in reverse order using python? I want to read a file from last line to first line.

相关标签:
21条回答
  • def reverse_lines(filename):
        y=open(filename).readlines()
        return y[::-1]
    
    0 讨论(0)
  • 2020-11-22 05:41
    def previous_line(self, opened_file):
            opened_file.seek(0, os.SEEK_END)
            position = opened_file.tell()
            buffer = bytearray()
            while position >= 0:
                opened_file.seek(position)
                position -= 1
                new_byte = opened_file.read(1)
                if new_byte == self.NEW_LINE:
                    parsed_string = buffer.decode()
                    yield parsed_string
                    buffer = bytearray()
                elif new_byte == self.EMPTY_BYTE:
                    continue
                else:
                    new_byte_array = bytearray(new_byte)
                    new_byte_array.extend(buffer)
                    buffer = new_byte_array
            yield None
    

    to use:

    opened_file = open(filepath, "rb")
    iterator = self.previous_line(opened_file)
    line = next(iterator) #one step
    close(opened_file)
    
    0 讨论(0)
  • 2020-11-22 05:43

    with open("filename") as f:

        print(f.read()[::-1])
    
    0 讨论(0)
  • 2020-11-22 05:44

    Thanks for the answer @srohde. It has a small bug checking for newline character with 'is' operator, and I could not comment on the answer with 1 reputation. Also I'd like to manage file open outside because that enables me to embed my ramblings for luigi tasks.

    What I needed to change has the form:

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

    I'd love to change to:

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

    Here is a modified answer that wants a file handle and keeps newlines:

    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
    
    0 讨论(0)
  • 2020-11-22 05:44

    a simple function to create a second file reversed (linux only):

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

    how to use

    tac('ordered.csv', 'reversed.csv')
    f = open('reversed.csv')
    
    0 讨论(0)
  • 2020-11-22 05:44

    Most of the answers need to read the whole file before doing anything. This sample reads increasingly large samples from the end.

    I only saw Murat Yükselen's answer while writing this answer. It's nearly the same, which I suppose is a good thing. The sample below also deals with \r and increases its buffersize at each step. I also have some unit tests to back this code up.

    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 讨论(0)
提交回复
热议问题