How to read a file in reverse order?

前端 未结 21 3007
礼貌的吻别
礼貌的吻别 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条回答
  •  耶瑟儿~
    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
    

提交回复
热议问题