파일을 역순으로 읽는 방법은 무엇입니까?


128

파이썬을 사용하여 파일을 역순으로 읽는 방법은 무엇입니까? 마지막 줄에서 첫 번째 줄까지 파일을 읽고 싶습니다.


7
"역순으로 읽으십시오"또는 "역순으로 줄을 처리하십시오"를 의미합니까? 차이가 있습니다. 첫 번째 파일은 파일이 동시에 메모리에 맞지 않을 수 있으므로 행을 역순으로 처리하려고하지만 전체 파일을 읽거나 되돌릴 수는 없습니다. 두 번째로, 전체 파일을 읽고 처리하기 전에 행 목록을 반대로 할 수 있습니다. 그래서 어느 것입니까?
Lasse V. Karlsen 2019


1
나는 이것을 권장한다-메모리 문제가없고 빠름 : stackoverflow.com/a/260433/1212562
Brian B

답변:


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

그리고 파이썬 3에서 :

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

192
아아, 전체 파일을 메모리에 맞출 수 없으면 작동하지 않습니다.
vy32

3
또한 게시 된 코드가 질문에 대답하지만 열려있는 파일을 닫을 때주의해야합니다. with문은 일반적으로 매우 고통입니다.
William

1
@MichaelDavidWatson : 원래 반복자를 먼저 메모리로 읽은 다음 첫 번째 반복자를 거꾸로 새 반복자를 제시하지 않고는 아닙니다.
Matt Joiner

3
@MichaelDavidWatson : 메모리로 파일을 읽지 않고 파일을 반대로 읽을 수는 있지만 사소하지 않으며 상당한 시스템 호출 낭비를 피하기 위해 많은 버퍼 shenanigan이 필요합니다. 또한 파일이 사용 가능한 메모리를 초과하는 경우 전체 메모리를 메모리로 읽는 것보다 낫지 만 성능이 매우 저하됩니다.
Matt Joiner

1
@William 죄송합니다. 파일을 반복해서 닫은 상태에서 "열린 상태"를 사용하여 위의 솔루션을 어떻게 사용합니까?
BringBackCommodore64

146

발전기로 작성된 정확하고 효율적인 답변.

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 concat the segment to the last line of new chunk.
                # Instead, yield the segment first 
                if buffer[-1] != '\n':
                    lines[-1] += segment
                else:
                    yield segment
            segment = lines[0]
            for index in range(len(lines) - 1, 0, -1):
                if lines[index]:
                    yield lines[index]
        # Don't yield None if the file was empty
        if segment is not None:
            yield segment

4
python> = 3.2의 텍스트 파일에서는 작동하지 않습니다. 어떤 이유로 파일 끝을 기준으로 한 탐색이 더 이상 지원되지 않기 때문입니다. 에 의해 반환 된 파일의 크기를 저장 fh.seek(0, os.SEEK_END)하고 fh.seek(-offset, os.SEEK_END)너무 변경하여 수정 될 수 있습니다 fh.seek(file_size - offset).
levesque

9
편집이 끝나면 python 3.5에서 완벽하게 작동합니다. 질문에 대한 최고의 답변.
notbad.jpeg

3
python 2 에서이 변경 사항 을 되 돌리십시오 . fh.seek()리턴None
marengaz

1
텍스트 파일에서 예상대로 작동하지 않을 수 있습니다. 역순으로 블록을 올바르게 얻는 것은 바이너리 파일에서만 작동합니다. 이 문제는 다중 바이트 인코딩 (예컨대 텍스트 파일이다 utf8) seek()read()다른 크기를 참조. 그것은 또한 아마의 비 - 제로 첫 번째 인수 이유입니다 seek()상대가 os.SEEK_END지원되지 않습니다.
norok2

3
간단합니다 : 'aöaö'.encode()입니다 b'a\xc3\xb6a\xc3\xb6'. 당신이 디스크에 저장 한 후 텍스트 모드로 읽는다면, 당신이 할 때 seek(2)그 그래서 2 바이트로 이동합니다 seek(2); read(1)오류가 발생합니다 UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb6 in position 0: invalid start byte,하지만 당신이 할 경우 seek(0); read(2); read(1), 당신은 얻을 것이다 'a'당신이 기대했던, 즉 : seek()결코 인코딩하지 않습니다 인식, read()텍스트 모드에서 파일을 여는 경우입니다. 이제가 있으면 'aöaö' * 1000000블록이 올바르게 정렬되지 않은 것입니다.
norok2

23

이런 식으로 어떻습니까 :

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

파일은 문자 단위로 역순으로 읽히기 때문에 개별 행이 메모리에 맞는 한 매우 큰 파일에서도 작동합니다.


20

python module을 사용할 수도 있습니다 file_read_backwards.

pip install file_read_backwards(v1.2.1)을 통해 파일을 설치 한 후 다음을 통해 전체 파일을 메모리 효율적인 방식으로 뒤로 읽을 수 있습니다.

#!/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

"utf-8", "latin-1"및 "ascii"인코딩을 지원합니다.

python3에 대한 지원도 가능합니다. 추가 문서는 http://file-read-backwards.readthedocs.io/en/latest/readme.html 에서 찾을 수 있습니다.


이 솔루션에 감사드립니다. @srohde의 위의 솔루션은 그것이 어떻게 수행되는지 이해하는 데 도움이 되었기 때문에 위의 솔루션을 좋아합니다 (그러나 upvoted).하지만 개발자는 가능한 경우 기존 모듈을 사용하는 것을 선호하므로 이것에 대해 알게되어 기쁩니다.
joanis

1
이것은 UTF-8과 같은 멀티 바이트 인코딩에서 작동합니다. 찾기 / 읽기 솔루션은 다음을 수행하지 않습니다. seek ()는 바이트 단위로 카운트하고 read ()는 문자로 카운트합니다.
Jeremitu

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

당신이 리눅스에 있다면, 당신은 tac명령 을 사용할 수 있습니다 .

$ tac file

당신은 ActiveState에서 찾을 수 2 개 조리법 여기여기에


1
reversed ()가 반복 전에 전체 시퀀스를 소비하는지 궁금합니다. 문서에 따르면 __reversed__()메소드가 필요하지만 python2.5는 메소드가 없으면 커스텀 클래스에 대해 불평하지 않습니다.
muhuk

@muhuk, 아마 내가 그것을 역순으로 새로운리스트가 그에게 반복자 반환 생성 의심, 어떻게 든 그것을 캐시가
마 소목

1
@ 매트 : 그건 말도 안됩니다. 단순히 뒤에서 앞으로갑니다. len (L) -1은 뒤이고 0은 앞입니다. 나머지 사진을 찍을 수 있습니다.
Devin Jeanpierre

@ muhuk : 시퀀스는 의미있게 소비되지 않습니다 (전체 시퀀스를 반복 할 수는 있지만별로 중요하지는 않습니다). __reversed__방법은 필요하지 않으며, 그런 일이있을 사용하지 않았다. 객체가 제공 __len__하고 __getitem__제대로 작동하면 (dict와 같은 예외적 인 경우는 제외) 잘 작동합니다.
Devin Jeanpierre

@Devin Jeanpierre : readlines ()가 __reversed__?
Matt Joiner

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

이것은 버퍼보다 ​​큰 파일에 대해 잘못된 출력을 생성하는 것으로 보입니다. 내가 이해하는 것처럼 버퍼 크기의 덩어리에 걸쳐있는 행을 올바르게 처리하지 못합니다. 비슷한 질문에 다른 답변을 게시했습니다.
다리우스 베이컨

@Darius : 아 맞아, 나는 조금 놓친 것 같다. 지금 수정해야합니다.
Ignacio Vazquez-Abrams

옳아 보인다. O (N ^ 2)가 하나의 긴 줄인 큰 파일에서 작동하기 때문에 여전히 내 자신의 코드를 선호합니다. (내가 테스트 한 다른 질문에 대한 비슷한 답변에서 이러한 파일의 심각한 속도 저하가 발생했습니다.)
Darius Bacon

3
문제는 성능에 대해 언급하지 않았기 때문에 정규 표현식 인 성능 재난을 피할 수 없습니다. : P
Matt Joiner

더 많은 설명이 성능으로 유용 할 수 있으며 이것이 실제로 마지막 줄을 말하고 해당 부분 만 읽으려고 할 수 있다면 유용합니다.
user1767754

7

메모리에 맞지 않는 대용량 파일 (드문 경우는 아님)의 경우 허용되는 답변이 작동하지 않습니다.

다른 사람들이 지적했듯이 @srohde 답변 은 좋아 보이지만 다음 문제가 있습니다.

  • 파일 객체를 전달하고 읽을 인코딩을 결정하도록 사용자에게 맡길 수있는 경우 파일 열기가 중복되어 보입니다.
  • 파일 객체를 허용하도록 리팩토링하더라도 모든 인코딩에서 작동하지는 않습니다. utf-8인코딩 및 ASCII 이외의 내용이 포함 된 파일을 선택할 수 있습니다

    й

    전달 buf_size동일 1하고 것

    UnicodeDecodeError: 'utf8' codec can't decode byte 0xb9 in position 0: invalid start byte

    물론 텍스트가 더 클 buf_size수 있지만 선택되어 위와 같이 혼란스러운 오류가 발생할 수 있습니다.

  • 맞춤 줄 구분 기호를 지정할 수 없습니다.
  • 줄 구분 기호를 유지하도록 선택할 수 없습니다.

따라서 이러한 모든 문제를 고려하여 별도의 기능을 작성했습니다.

  • 바이트 스트림과 작동하는
  • 두 번째는 텍스트 스트림과 함께 작동하고 기본 바이트 스트림을 첫 번째 스트림에 위임하고 결과 행을 디코딩합니다.

우선 다음 유틸리티 함수를 정의 해 봅시다 :

ceil_division천장으로 나누기위한 ( //바닥이 있는 표준 나누기와 는 달리 , 이 스레드 에서 더 많은 정보를 찾을 수 있습니다 )

def ceil_division(left_number, right_number):
    """
    Divides given numbers with ceiling.
    """
    return -(-left_number // right_number)

split 오른쪽 끝에서 주어진 구분 기호로 문자열을 분할하여 유지할 수 있습니다.

def split(string, separator, keep_separator):
    """
    Splits given string by given separator.
    """
    parts = string.split(separator)
    if keep_separator:
        *parts, last_part = parts
        parts = [part + separator for part in parts]
        if last_part:
            return parts + [last_part]
    return parts

read_batch_from_end 이진 스트림의 오른쪽 끝에서 배치를 읽으려면

def read_batch_from_end(byte_stream, size, end_position):
    """
    Reads batch from the end of given byte stream.
    """
    if end_position > size:
        offset = end_position - size
    else:
        offset = 0
        size = end_position
    byte_stream.seek(offset)
    return byte_stream.read(size)

그런 다음 바이트 스트림을 읽는 기능을 역순으로 정의 할 수 있습니다

import functools
import itertools
import os
from operator import methodcaller, sub


def reverse_binary_stream(byte_stream, batch_size=None,
                          lines_separator=None,
                          keep_lines_separator=True):
    if lines_separator is None:
        lines_separator = (b'\r', b'\n', b'\r\n')
        lines_splitter = methodcaller(str.splitlines.__name__,
                                      keep_lines_separator)
    else:
        lines_splitter = functools.partial(split,
                                           separator=lines_separator,
                                           keep_separator=keep_lines_separator)
    stream_size = byte_stream.seek(0, os.SEEK_END)
    if batch_size is None:
        batch_size = stream_size or 1
    batches_count = ceil_division(stream_size, batch_size)
    remaining_bytes_indicator = itertools.islice(
            itertools.accumulate(itertools.chain([stream_size],
                                                 itertools.repeat(batch_size)),
                                 sub),
            batches_count)
    try:
        remaining_bytes_count = next(remaining_bytes_indicator)
    except StopIteration:
        return

    def read_batch(position):
        result = read_batch_from_end(byte_stream,
                                     size=batch_size,
                                     end_position=position)
        while result.startswith(lines_separator):
            try:
                position = next(remaining_bytes_indicator)
            except StopIteration:
                break
            result = (read_batch_from_end(byte_stream,
                                          size=batch_size,
                                          end_position=position)
                      + result)
        return result

    batch = read_batch(remaining_bytes_count)
    segment, *lines = lines_splitter(batch)
    yield from reverse(lines)
    for remaining_bytes_count in remaining_bytes_indicator:
        batch = read_batch(remaining_bytes_count)
        lines = lines_splitter(batch)
        if batch.endswith(lines_separator):
            yield segment
        else:
            lines[-1] += segment
        segment, *lines = lines
        yield from reverse(lines)
    yield segment

마지막으로 텍스트 파일을 되 돌리는 기능은 다음과 같이 정의 할 수 있습니다.

import codecs


def reverse_file(file, batch_size=None, 
                 lines_separator=None,
                 keep_lines_separator=True):
    encoding = file.encoding
    if lines_separator is not None:
        lines_separator = lines_separator.encode(encoding)
    yield from map(functools.partial(codecs.decode,
                                     encoding=encoding),
                   reverse_binary_stream(
                           file.buffer,
                           batch_size=batch_size,
                           lines_separator=lines_separator,
                           keep_lines_separator=keep_lines_separator))

테스트

준비

fsutil명령을 사용하여 4 개의 파일을 생성했습니다 .

  1. 내용이없는 empty.txt , 크기 0MB
  2. 1MB 크기의 tiny.txt
  3. 크기가 10MB 인 small.txt
  4. 크기가 50MB 인 large.txt

또한 파일 경로 대신 파일 객체로 작업하기 위해 @srohde 솔루션을 리팩터링했습니다.

테스트 스크립트

from timeit import Timer

repeats_count = 7
number = 1
create_setup = ('from collections import deque\n'
                'from __main__ import reverse_file, reverse_readline\n'
                'file = open("{}")').format
srohde_solution = ('with file:\n'
                   '    deque(reverse_readline(file,\n'
                   '                           buf_size=8192),'
                   '          maxlen=0)')
azat_ibrakov_solution = ('with file:\n'
                         '    deque(reverse_file(file,\n'
                         '                       lines_separator="\\n",\n'
                         '                       keep_lines_separator=False,\n'
                         '                       batch_size=8192), maxlen=0)')
print('reversing empty file by "srohde"',
      min(Timer(srohde_solution,
                create_setup('empty.txt')).repeat(repeats_count, number)))
print('reversing empty file by "Azat Ibrakov"',
      min(Timer(azat_ibrakov_solution,
                create_setup('empty.txt')).repeat(repeats_count, number)))
print('reversing tiny file (1MB) by "srohde"',
      min(Timer(srohde_solution,
                create_setup('tiny.txt')).repeat(repeats_count, number)))
print('reversing tiny file (1MB) by "Azat Ibrakov"',
      min(Timer(azat_ibrakov_solution,
                create_setup('tiny.txt')).repeat(repeats_count, number)))
print('reversing small file (10MB) by "srohde"',
      min(Timer(srohde_solution,
                create_setup('small.txt')).repeat(repeats_count, number)))
print('reversing small file (10MB) by "Azat Ibrakov"',
      min(Timer(azat_ibrakov_solution,
                create_setup('small.txt')).repeat(repeats_count, number)))
print('reversing large file (50MB) by "srohde"',
      min(Timer(srohde_solution,
                create_setup('large.txt')).repeat(repeats_count, number)))
print('reversing large file (50MB) by "Azat Ibrakov"',
      min(Timer(azat_ibrakov_solution,
                create_setup('large.txt')).repeat(repeats_count, number)))

참고 : collections.deque클래스를 사용 하여 발전기를 배출했습니다.

출력

Windows 10의 PyPy 3.5의 경우 :

reversing empty file by "srohde" 8.31e-05
reversing empty file by "Azat Ibrakov" 0.00016090000000000028
reversing tiny file (1MB) by "srohde" 0.160081
reversing tiny file (1MB) by "Azat Ibrakov" 0.09594989999999998
reversing small file (10MB) by "srohde" 8.8891863
reversing small file (10MB) by "Azat Ibrakov" 5.323388100000001
reversing large file (50MB) by "srohde" 186.5338368
reversing large file (50MB) by "Azat Ibrakov" 99.07450229999998

Windows 10의 CPython 3.5의 경우 :

reversing empty file by "srohde" 3.600000000000001e-05
reversing empty file by "Azat Ibrakov" 4.519999999999958e-05
reversing tiny file (1MB) by "srohde" 0.01965560000000001
reversing tiny file (1MB) by "Azat Ibrakov" 0.019207699999999994
reversing small file (10MB) by "srohde" 3.1341862999999996
reversing small file (10MB) by "Azat Ibrakov" 3.0872588000000007
reversing large file (50MB) by "srohde" 82.01206720000002
reversing large file (50MB) by "Azat Ibrakov" 82.16775059999998

우리가 볼 수 있듯이 원래 솔루션처럼 작동하지만 더 일반적이며 위에 나열된 단점이 없습니다.


광고

나는 잘 테스트 된 기능 / 인용 유틸리티가 많은 패키지0.3.0 버전 ( Python 3.5 + 필요)에 이것을 추가했습니다 .lz

처럼 사용할 수 있습니다

 import io
 from lz.iterating import reverse
 ...
 with open('path/to/file') as file:
     for line in reverse(file, batch_size=io.DEFAULT_BUFFER_SIZE):
         print(line)

그것은 모든 표준 인코딩을 지원 합니다 ( utf-7내가 인코딩 할 수 있는 문자열을 생성 하기 위한 전략 을 정의하기가 어렵 기 때문에 제외 ).


2

여기서 내 구현을 찾을 수 있습니다. "buffer"변수를 변경하여 램 사용을 제한 할 수 있습니다. 프로그램이 처음에 빈 줄을 인쇄하는 버그가 있습니다.

또한 버퍼 바이트를 초과하는 줄 바꿈이 없으면 램 사용량이 증가 할 수 있습니다. 새 줄을 볼 때까지 "leak"변수가 증가합니다 ( "\ n").

이것은 또한 총 메모리보다 큰 16GB 파일에서도 작동합니다.

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

답변 @srohde에 감사드립니다. 'is'연산자를 사용하여 줄 바꿈 문자를 검사하는 작은 버그가 있으며 1 평판으로 답변에 댓글을 달 수 없습니다. 또한 luigi 작업에 대한 내 문제를 포함시킬 수 있기 때문에 외부에서 열린 파일을 관리하고 싶습니다.

내가 변경 해야하는 것은 다음과 같은 형식입니다.

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

나는 다음과 같이 바꾸고 싶다 :

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

다음은 파일 핸들을 원하고 개행을 유지하는 수정 된 답변입니다.

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

1

두 번째 파일을 반대로 만드는 간단한 함수 (Linux 만 해당) :

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

사용하는 방법

tac('ordered.csv', 'reversed.csv')
f = open('reversed.csv')

파이썬에서 목표를 달성하는 방법이 목표라고 생각합니다. 또한이 솔루션은 탁월한 솔루션이지만 * Nix 시스템에서만 작동합니다. 본질적으로 쉘 유틸리티를 실행하라는 프롬프트로 Python을 사용합니다.
Alexander Huszagh

1
이 코드에는 현재 작성된 주요 보안 버그가 있습니다. 로 만들 mv mycontent.txt $'hello $(rm -rf $HOME) world.txt'거나 신뢰할 수없는 사용자가 제공 한 출력 파일 이름을 사용하여 파일을 반대로 바꾸려고하면 어떻게합니까? 임의의 파일 이름을 안전하게 처리하려면 더주의해야합니다. subprocess.Popen(['tac', file1], stdout=open(file2, 'w'))예를 들어 안전합니다.
Charles Duffy

기존 코드는 또한 공백, 와일드 카드 및 & c가있는 파일을 올바르게 처리하지 않습니다.
Charles Duffy


1

f로 open ( "filename") 사용 :

    print(f.read()[::-1])

이것이 전체 파일을 읽습니까? 큰 파일에서도 안전한가요? 이것은 매우 쉽고 현실적인 방법으로 보이지만 위의 질문에 대해서는 확실하지 않습니다 ..이 방법으로 파일을 검색하고 싶습니다 (re 사용).
ikwyl6

@ ikwyl6 이것은와 동일해야합니다 list(reversed(f.read())).
AMC


0

with파일 작업시 항상 모든 것을 처리하므로 항상 사용 하십시오.

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

또는 파이썬 3에서 :

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

0

먼저 파일을 읽기 형식으로 열고 변수에 저장 한 다음 쓰기 형식으로 두 번째 파일을 열고 [::-1] 슬라이스를 사용하여 변수를 쓰거나 추가하여 파일을 완전히 되돌려 야합니다. readlines ()를 사용하여 행 목록으로 만들 수 있습니다.

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

대부분의 답변은 무엇이든하기 전에 전체 파일을 읽어야합니다. 이 샘플은 끝에서 점점 더 큰 샘플 읽습니다 .

이 답변을 쓰는 ​​동안 Murat Yükselen의 답변 만 보았습니다. 거의 동일합니다. 좋은 생각입니다. 아래 샘플은 또한 \ r을 다루고 각 단계에서 버퍼 크기를 증가시킵니다. 이 코드를 백업하기위한 단위 테스트 도 있습니다 .

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

파일을 한 줄씩 읽고 목록에 역순으로 추가하십시오.

다음은 코드 예제입니다.

reverse = []
with open("file.txt", "r") as file:
    for line in file:
        line = line.strip()
         reverse[0:0] = line

이것은 받아 들여진 대답 에서 해결책의 열등한 버전처럼 보입니다 .
AMC


0
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

쓰다:

opened_file = open(filepath, "rb")
iterator = self.previous_line(opened_file)
line = next(iterator) #one step
close(opened_file)

-3

나는 얼마 전에 이것을해야했고 아래 코드를 사용했다. 쉘로 파이프됩니다. 더 이상 완전한 스크립트가없는 것이 두렵습니다. unixish 운영 체제 인 경우 "tac"를 사용할 수 있지만 Mac OSX tac 명령이 작동하지 않으면 tail -r을 사용하십시오. 아래 코드 스 니펫은 현재 사용중인 플랫폼을 테스트하고 그에 따라 명령을 조정합니다

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

포스터가 파이썬 답변을 찾고 있습니다.
mikemaccana

글쎄, 그것은 불완전한 것처럼 보이지만 파이썬 답변입니다.
DrDee

2
그하지, 시스템 명령을 사용하여 크로스 플랫폼하지 =하지 파이썬
Phyo Arkar Lwin

포스터는 코드 스 니펫이 실제로 쓰여진 "파이썬 사용"이라는 답변을 찾고 있습니다. 그러나 나는 게시 된 다른 많은 것들과 비교할 때 그다지 좋은 해결책이 아니라는 데 동의합니다.
jeorgen

1
이 스 니펫은 정확성을 평가하기에 충분하지 않지만 (호출의 다른 부분은 표시되지 않음) 문자열에 쉘 명령을 저장하는 것은 의심의 여지가 있습니다. 관리.
Charles Duffy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.