비슷한 질문 에 대한 나의 답변 에 대해 해설자의 의견에 따라 답변을 게시같은 기술이 파일의 마지막 줄을 변경하는 데 사용 것입니다.
크기가 큰 파일의 mmap
경우 가장 좋은 방법입니다. 기존 mmap
답변 을 개선하기 위해이 버전은 Windows와 Linux 사이에서 이식 가능하며 더 빠르게 실행됩니다 (GB 범위의 파일로 32 비트 Python에서 수정하지 않으면 작동하지 않지만 다른 처리 방법에 대한 힌트 는 다른 답변을 참조하십시오) , 그리고 파이썬 2에서 작동하도록 수정하기 위해 ).
import io # Gets consistent version of open for both Py2.7 and Py3.x
import itertools
import mmap
def skip_back_lines(mm, numlines, startidx):
'''Factored out to simplify handling of n and offset'''
for _ in itertools.repeat(None, numlines):
startidx = mm.rfind(b'\n', 0, startidx)
if startidx < 0:
break
return startidx
def tail(f, n, offset=0):
# Reopen file in binary mode
with io.open(f.name, 'rb') as binf, mmap.mmap(binf.fileno(), 0, access=mmap.ACCESS_READ) as mm:
# len(mm) - 1 handles files ending w/newline by getting the prior line
startofline = skip_back_lines(mm, offset, len(mm) - 1)
if startofline < 0:
return [] # Offset lines consumed whole file, nothing to return
# If using a generator function (yield-ing, see below),
# this should be a plain return, no empty list
endoflines = startofline + 1 # Slice end to omit offset lines
# Find start of lines to capture (add 1 to move from newline to beginning of following line)
startofline = skip_back_lines(mm, n, startofline) + 1
# Passing True to splitlines makes it return the list of lines without
# removing the trailing newline (if any), so list mimics f.readlines()
return mm[startofline:endoflines].splitlines(True)
# If Windows style \r\n newlines need to be normalized to \n, and input
# is ASCII compatible, can normalize newlines with:
# return mm[startofline:endoflines].replace(os.linesep.encode('ascii'), b'\n').splitlines(True)
이것은 꼬리가있는 줄의 수가 작아서 한 번에 메모리로 안전하게 읽을 수있을 정도로 작다고 가정합니다. 마지막 줄을 다음과 같이 바꾸어 생성기 함수로 만들고 한 번에 한 줄씩 수동으로 읽을 수도 있습니다.
mm.seek(startofline)
# Call mm.readline n times, or until EOF, whichever comes first
# Python 3.2 and earlier:
for line in itertools.islice(iter(mm.readline, b''), n):
yield line
# 3.3+:
yield from itertools.islice(iter(mm.readline, b''), n)
마지막으로,이 (사용에 필요한 바이너리 모드로 읽기 mmap
가 제공되도록) str
라인 (Py2)과 bytes
선 (Py3를); unicode
(Py2) 또는 str
(Py3) 을 원하는 경우 반복 접근 방식을 조정하여 사용자를 디코딩하고 개행을 수정할 수 있습니다.
lines = itertools.islice(iter(mm.readline, b''), n)
if f.encoding: # Decode if the passed file was opened with a specific encoding
lines = (line.decode(f.encoding) for line in lines)
if 'b' not in f.mode: # Fix line breaks if passed file opened in text mode
lines = (line.replace(os.linesep, '\n') for line in lines)
# Python 3.2 and earlier:
for line in lines:
yield line
# 3.3+:
yield from lines
참고 : 테스트 할 Python에 액세스 할 수없는 컴퓨터 에서이 모든 것을 입력했습니다. 내가 무엇인가를 입력하면 알려주십시오. 이것은 내가 작동해야 한다고 생각 하는 다른 대답 과 충분히 비슷 하지만 조정 (예 : 처리 )으로 미묘한 오류가 발생할 수 있습니다. 실수가 있으면 의견에 알려주십시오.offset
seek(0,2)
thentell()
) 를 얻 도록 시작하고 그 값을 사용하여 시작을 기준으로 찾습니다.