source

tail과 유사한 파일의 마지막 n 행을 가져옵니다.

goodcode 2022. 9. 8. 21:52
반응형

tail과 유사한 파일의 마지막 n 행을 가져옵니다.

웹 응용 프로그램의 로그 파일 뷰어를 작성하고 로그 파일의 행까지 페이지 번호를 매기고 싶습니다.파일 내의 아이템은 최신 아이템이 맨 아래에 있는 라인 베이스입니다.

나는 ★★★★★★★★★★★★★★★★★★★★★★★★★tail()n밑에서부터의 선과 오프셋을 지원합니다.이게 내가 생각해낸 모자야

def tail(f, n, offset=0):
    """Reads a n lines from f with an offset of offset lines."""
    avg_line_length = 74
    to_read = n + offset
    while 1:
        try:
            f.seek(-(avg_line_length * to_read), 2)
        except IOError:
            # woops.  apparently file is smaller than what we want
            # to step back, go to the beginning instead
            f.seek(0)
        pos = f.tell()
        lines = f.read().splitlines()
        if len(lines) >= to_read or pos == 0:
            return lines[-to_read:offset and -offset or None]
        avg_line_length *= 1.3

이것이 합리적인 접근법입니까?오프셋을 사용하여 로그 파일을 테일링하는 권장 방법은 무엇입니까?

이게 당신보다 빠를 수도 있어요.회선 길이에 관한 전제 조건은 없습니다.올바른 수의 '\n' 문자가 검색될 때까지 파일을 한 블록씩 되돌립니다.

def tail( f, lines=20 ):
    total_lines_wanted = lines

    BLOCK_SIZE = 1024
    f.seek(0, 2)
    block_end_byte = f.tell()
    lines_to_go = total_lines_wanted
    block_number = -1
    blocks = [] # blocks of size BLOCK_SIZE, in reverse order starting
                # from the end of the file
    while lines_to_go > 0 and block_end_byte > 0:
        if (block_end_byte - BLOCK_SIZE > 0):
            # read the last block we haven't yet read
            f.seek(block_number*BLOCK_SIZE, 2)
            blocks.append(f.read(BLOCK_SIZE))
        else:
            # file too small, start from begining
            f.seek(0,0)
            # only read what was not read
            blocks.append(f.read(block_end_byte))
        lines_found = blocks[-1].count('\n')
        lines_to_go -= lines_found
        block_end_byte -= BLOCK_SIZE
        block_number -= 1
    all_read_text = ''.join(reversed(blocks))
    return '\n'.join(all_read_text.splitlines()[-total_lines_wanted:])

저는 줄의 길이에 대한 까다로운 추정을 좋아하지 않습니다.실제로 그런 것은 알 수 없습니다.

일반적으로 루프를 통과하는 첫 번째 또는 두 번째 경로 상에 마지막 20개의 행이 있습니다.74글자가 사실 정확하다면 블록 크기를 2048로 만들면 20줄은 거의 바로 꼬리가 잡힙니다.

또, 물리적인 OS 블록과의 정렬을 세밀하게 하기 위해서, 많은 두뇌의 칼로리를 소비하지 않습니다.이러한 높은 수준의 I/O 패키지를 사용하면 OS 블록 경계에 맞추려고 하면 성능 저하가 발생하지 않을 것입니다.낮은 수준의 I/O를 사용하면 속도가 향상될 수 있습니다.


갱신하다

Python 3.2 이상의 경우 텍스트 파일(모드 문자열에 "b"가 없이 열린 파일)에서 파일의 시작 부분만 검색할 수 있으므로 바이트 단위로 프로세스를 수행합니다(Seek(0, 2)로 파일 끝을 찾는 것은 예외임).

::f = open('C:/.../../apache_logs.txt', 'rb')

 def tail(f, lines=20):
    total_lines_wanted = lines

    BLOCK_SIZE = 1024
    f.seek(0, 2)
    block_end_byte = f.tell()
    lines_to_go = total_lines_wanted
    block_number = -1
    blocks = []
    while lines_to_go > 0 and block_end_byte > 0:
        if (block_end_byte - BLOCK_SIZE > 0):
            f.seek(block_number*BLOCK_SIZE, 2)
            blocks.append(f.read(BLOCK_SIZE))
        else:
            f.seek(0,0)
            blocks.append(f.read(block_end_byte))
        lines_found = blocks[-1].count(b'\n')
        lines_to_go -= lines_found
        block_end_byte -= BLOCK_SIZE
        block_number -= 1
    all_read_text = b''.join(reversed(blocks))
    return b'\n'.join(all_read_text.splitlines()[-total_lines_wanted:])

Python 2의 unix와 같은 시스템이 다음 작업을 수행할 수 있다고 가정합니다.

import os
def tail(f, n, offset=0):
  stdin,stdout = os.popen2("tail -n "+n+offset+" "+f)
  stdin.close()
  lines = stdout.readlines(); stdout.close()
  return lines[:,-offset]

python 3의 경우 다음을 수행할 수 있습니다.

import subprocess
def tail(f, n, offset=0):
    proc = subprocess.Popen(['tail', '-n', n + offset, f], stdout=subprocess.PIPE)
    lines = proc.stdout.readlines()
    return lines[:, -offset]

제 대답은 이렇습니다.순수한 비단뱀.시간을 쓰면 꽤 빠른 것 같아요.100,000 행이 있는 로그파일의 100 행의 테일링:

>>> timeit.timeit('tail.tail(f, 100, 4098)', 'import tail; f = open("log.txt", "r");', number=10)
0.0014600753784179688
>>> timeit.timeit('tail.tail(f, 100, 4098)', 'import tail; f = open("log.txt", "r");', number=100)
0.00899195671081543
>>> timeit.timeit('tail.tail(f, 100, 4098)', 'import tail; f = open("log.txt", "r");', number=1000)
0.05842900276184082
>>> timeit.timeit('tail.tail(f, 100, 4098)', 'import tail; f = open("log.txt", "r");', number=10000)
0.5394978523254395
>>> timeit.timeit('tail.tail(f, 100, 4098)', 'import tail; f = open("log.txt", "r");', number=100000)
5.377126932144165

코드는 다음과 같습니다.

import os


def tail(f, lines=1, _buffer=4098):
    """Tail a file and get X lines from the end"""
    # place holder for the lines found
    lines_found = []

    # block counter will be multiplied by buffer
    # to get the block size from the end
    block_counter = -1

    # loop until we find X lines
    while len(lines_found) < lines:
        try:
            f.seek(block_counter * _buffer, os.SEEK_END)
        except IOError:  # either file is too small, or too many lines requested
            f.seek(0)
            lines_found = f.readlines()
            break

        lines_found = f.readlines()

        # we found enough lines, get out
        # Removed this line because it was redundant the while will catch
        # it, I left it for history
        # if len(lines_found) > lines:
        #    break

        # decrement the block counter to get the
        # next X bytes
        block_counter -= 1

    return lines_found[-lines:]

파일 전체를 읽을 수 있는 경우 deque를 사용합니다.

from collections import deque
deque(f, maxlen=n)

2.6 이전 버전에서는 decues에는 maxlen 옵션이 없었지만 구현이 용이합니다.

import itertools
def maxque(items, size):
    items = iter(items)
    q = deque(itertools.islice(items, size))
    for item in items:
        del q[0]
        q.append(item)
    return q

파일을 처음부터 읽어야 하는 경우 gallop(지수) 검색을 사용합니다.

def tail(f, n):
    assert n >= 0
    pos, lines = n+1, []
    while len(lines) <= n:
        try:
            f.seek(-pos, 2)
        except IOError:
            f.seek(0)
            break
        finally:
            lines = list(f)
        pos *= 2
    return lines[-n:]

위의 S.Lott의 답변은 나에게 거의 통하지만 결국 부분적인 행이 생기게 된다.데이터가 읽기 블록을 역순으로 유지하므로 블록 경계에 있는 데이터가 손상되는 것으로 나타났습니다..join(데이터)이 호출되면 블록의 순서가 잘못되었습니다.이것으로 해결됩니다.

def tail(f, window=20):
    """
    Returns the last `window` lines of file `f` as a list.
    f - a byte file-like object
    """
    if window == 0:
        return []
    BUFSIZ = 1024
    f.seek(0, 2)
    bytes = f.tell()
    size = window + 1
    block = -1
    data = []
    while size > 0 and bytes > 0:
        if bytes - BUFSIZ > 0:
            # Seek back one whole BUFSIZ
            f.seek(block * BUFSIZ, 2)
            # read BUFFER
            data.insert(0, f.read(BUFSIZ))
        else:
            # file too small, start from begining
            f.seek(0,0)
            # only read what was not read
            data.insert(0, f.read(bytes))
        linesFound = data[0].count('\n')
        size -= linesFound
        bytes -= BUFSIZ
        block -= 1
    return ''.join(data).splitlines()[-window:]

결국 내가 사용하게 된 코드.저는 이게 지금까지의 것 중 최고라고 생각합니다.

def tail(f, n, offset=None):
    """Reads a n lines from f with an offset of offset lines.  The return
    value is a tuple in the form ``(lines, has_more)`` where `has_more` is
    an indicator that is `True` if there are more lines in the file.
    """
    avg_line_length = 74
    to_read = n + (offset or 0)

    while 1:
        try:
            f.seek(-(avg_line_length * to_read), 2)
        except IOError:
            # woops.  apparently file is smaller than what we want
            # to step back, go to the beginning instead
            f.seek(0)
        pos = f.tell()
        lines = f.read().splitlines()
        if len(lines) >= to_read or pos == 0:
            return lines[-to_read:offset and -offset or None], \
                   len(lines) > to_read or pos > 0
        avg_line_length *= 1.3

mmap을 통한 심플하고 빠른 솔루션:

import mmap
import os

def tail(filename, n):
    """Returns last n lines from the filename. No exception handling"""
    size = os.path.getsize(filename)
    with open(filename, "rb") as f:
        # for Windows the mmap parameters are different
        fm = mmap.mmap(f.fileno(), 0, mmap.MAP_SHARED, mmap.PROT_READ)
        try:
            for i in xrange(size - 1, -1, -1):
                if fm[i] == '\n':
                    n -= 1
                    if n == -1:
                        break
            return fm[i + 1 if i else 0:].splitlines()
        finally:
            fm.close()

@papercrane python3 。을 열 때 '열다'로 엽니다.open(filename, 'rb')아,아,아,아,아,아,아,아,아,아,아,아,아,아,아.

def tail(f, window=20):
    """Returns the last `window` lines of file `f` as a list.
    """
    if window == 0:
        return []

    BUFSIZ = 1024
    f.seek(0, 2)
    remaining_bytes = f.tell()
    size = window + 1
    block = -1
    data = []

    while size > 0 and remaining_bytes > 0:
        if remaining_bytes - BUFSIZ > 0:
            # Seek back one whole BUFSIZ
            f.seek(block * BUFSIZ, 2)
            # read BUFFER
            bunch = f.read(BUFSIZ)
        else:
            # file too small, start from beginning
            f.seek(0, 0)
            # only read what was not read
            bunch = f.read(remaining_bytes)

        bunch = bunch.decode('utf-8')
        data.insert(0, bunch)
        size -= bunch.count('\n')
        remaining_bytes -= BUFSIZ
        block -= 1

    return ''.join(data).splitlines()[-window:]

은 '우리'를 사용하는 입니다.deque:

from collections import deque

def tail(filename, n=10):
    with open(filename) as f:
        return deque(f, n)

비슷한 질문에 대한 코멘트의 요청에 따라 답변을 올렸습니다.파일의 마지막 줄을 변환하는 데 같은 기술이 사용되었습니다.

상당한 크기의 파일일 경우 이 작업을 수행하는 것이 가장 좋습니다.기존의 것을 개선하다mmap답변: 이 버전은 Windows와 Linux 간에 이식 가능하며 더 빠르게 실행될 것입니다(GB 범위의 파일을 가진 32비트 Python에서는 일부 수정 없이는 작동하지 않지만, 이 문제를 처리하고 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); 행(Py3)unicode (Py2) 또str(하면, 과 같은 어프로치를 하거나,회선을 하거나 할 수 있습니다.

        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는, 에러가 이 있습니다).★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

python3는 삽입하지 않고 추가 및 반전되는 더욱 깔끔한 버전입니다.

def tail(f, window=1):
    """
    Returns the last `window` lines of file `f` as a list of bytes.
    """
    if window == 0:
        return b''
    BUFSIZE = 1024
    f.seek(0, 2)
    end = f.tell()
    nlines = window + 1
    data = []
    while nlines > 0 and end > 0:
        i = max(0, end - BUFSIZE)
        nread = min(end, BUFSIZE)

        f.seek(i)
        chunk = f.read(nread)
        data.append(chunk)
        nlines -= chunk.count(b'\n')
        end -= nread
    return b'\n'.join(b''.join(reversed(data)).splitlines()[-window:])

다음과 같이 사용합니다.

with open(path, 'rb') as f:
    last_lines = tail(f, 3).decode('utf-8')

S를 기준으로 합니다.Lott의 최고 투표 응답 (2008년 7월 25일 21시 43분)단, 소형 파일용 수정.

def tail(the_file, lines_2find=20):  
    the_file.seek(0, 2)                         #go to end of file
    bytes_in_file = the_file.tell()             
    lines_found, total_bytes_scanned = 0, 0
    while lines_2find+1 > lines_found and bytes_in_file > total_bytes_scanned: 
        byte_block = min(1024, bytes_in_file-total_bytes_scanned)
        the_file.seek(-(byte_block+total_bytes_scanned), 2)
        total_bytes_scanned += byte_block
        lines_found += the_file.read(1024).count('\n')
    the_file.seek(-total_bytes_scanned, 2)
    line_list = list(the_file.readlines())
    return line_list[-lines_2find:]

    #we read at least 21 line breaks from the bottom, block by block for speed
    #21 to ensure we don't get a half line

이게 도움이 됐으면 좋겠네요.

tail on pypi에는 pip을 사용하여 설치할 수 있는 몇 가지 기존 구현이 있습니다.

  • mtFileUtil
  • 멀티테일
  • log4tailer
  • ...

상황에 따라서는 이러한 기존 도구 중 하나를 사용하면 이점이 있을 수 있습니다.

심플:

with open("test.txt") as f:
data = f.readlines()
tail = data[-2:]
print(''.join(tail)

나는 위의 Popen이 최선의 해결책이라는 것을 알았다.빠르고 지저분하며 유닉스 머신의 python 2.6에서 동작합니다. 저는 다음을 사용했습니다.

def GetLastNLines(self, n, fileName):
    """
    Name:           Get LastNLines
    Description:        Gets last n lines using Unix tail
    Output:         returns last n lines of a file
    Keyword argument:
    n -- number of last lines to return
    filename -- Name of the file you need to tail into
    """
    p = subprocess.Popen(['tail','-n',str(n),self.__fileName], stdout=subprocess.PIPE)
    soutput, sinput = p.communicate()
    return soutput

southput have에는 코드의 마지막 n 행이 포함됩니다.한 줄씩 사우스풋을 반복하려면 다음 작업을 수행합니다.

for line in GetLastNLines(50,'myfile.log').split('\n'):
    print line

매우 큰 파일(tail을 사용하는 로그 파일 상황에서 흔히 볼 수 있는)의 효율성을 위해 일반적으로 파일 전체를 읽지 않도록 합니다(한 번에 전체 파일을 메모리에 읽지 않고 읽더라도). 단, 오프셋을 문자가 아닌 행으로 계산해야 합니다.한 가지 방법은 seek() char를 한 글자씩 거꾸로 읽는 것입니다만, 이것은 매우 느립니다.대신 더 큰 블록으로 처리하는 것이 좋습니다.

여기서 사용할 수 있는 파일을 거꾸로 읽기 위해 얼마 전에 작성한 유틸리티 기능이 있습니다.

import os, itertools

def rblocks(f, blocksize=4096):
    """Read file as series of blocks from end of file to start.

    The data itself is in normal order, only the order of the blocks is reversed.
    ie. "hello world" -> ["ld","wor", "lo ", "hel"]
    Note that the file must be opened in binary mode.
    """
    if 'b' not in f.mode.lower():
        raise Exception("File must be opened using binary mode.")
    size = os.stat(f.name).st_size
    fullblocks, lastblock = divmod(size, blocksize)

    # The first(end of file) block will be short, since this leaves 
    # the rest aligned on a blocksize boundary.  This may be more 
    # efficient than having the last (first in file) block be short
    f.seek(-lastblock,2)
    yield f.read(lastblock)

    for i in range(fullblocks-1,-1, -1):
        f.seek(i * blocksize)
        yield f.read(blocksize)

def tail(f, nlines):
    buf = ''
    result = []
    for block in rblocks(f):
        buf = block + buf
        lines = buf.splitlines()

        # Return all lines except the first (since may be partial)
        if lines:
            result.extend(lines[1:]) # First line may not be complete
            if(len(result) >= nlines):
                return result[-nlines:]

            buf = lines[0]

    return ([buf]+result)[-nlines:]


f=open('file_to_tail.txt','rb')
for line in tail(f, 20):
    print line

[편집] 보다 구체적인 버전 추가 (2회 되돌릴 필요가 없음

f.seek(0, 2)를 사용하여 파일 끝으로 이동한 후 다음 readline() 대체로 한 줄씩 오프라인을 읽을 수 있습니다.

def readline_backwards(self, f):
    backline = ''
    last = ''
    while not last == '\n':
        backline = last + backline
        if f.tell() <= 0:
            return backline
        f.seek(-1, 1)
        last = f.read(1)
        f.seek(-1, 1)
    backline = last
    last = ''
    while not last == '\n':
        backline = last + backline
        if f.tell() <= 0:
            return backline
        f.seek(-1, 1)
        last = f.read(1)
        f.seek(-1, 1)
    f.seek(1, 1)
    return backline

Eyecue 응답(Jun 10 '10 at 21:28): 이 클래스는 파일 객체에 head() 메서드와 tail() 메서드를 추가합니다.

class File(file):
    def head(self, lines_2find=1):
        self.seek(0)                            #Rewind file
        return [self.next() for x in xrange(lines_2find)]

    def tail(self, lines_2find=1):  
        self.seek(0, 2)                         #go to end of file
        bytes_in_file = self.tell()             
        lines_found, total_bytes_scanned = 0, 0
        while (lines_2find+1 > lines_found and
               bytes_in_file > total_bytes_scanned): 
            byte_block = min(1024, bytes_in_file-total_bytes_scanned)
            self.seek(-(byte_block+total_bytes_scanned), 2)
            total_bytes_scanned += byte_block
            lines_found += self.read(1024).count('\n')
        self.seek(-total_bytes_scanned, 2)
        line_list = list(self.readlines())
        return line_list[-lines_2find:]

사용방법:

f = File('path/to/file', 'r')
f.head(3)
f.tail(3)

이러한 해결 방법 중 일부는 파일이 \n으로 끝나지 않거나 첫 번째 줄 전체를 읽는 데 문제가 있습니다.

def tail(file, n=1, bs=1024):
    f = open(file)
    f.seek(-1,2)
    l = 1-f.read(1).count('\n') # If file doesn't end in \n, count it anyway.
    B = f.tell()
    while n >= l and B > 0:
            block = min(bs, B)
            B -= block
            f.seek(B, 0)
            l += f.read(block).count('\n')
    f.seek(B, 0)
    l = min(l,n) # discard first (incomplete) line if l > n
    lines = f.readlines()[-l:]
    f.close()
    return lines

다음은 매우 간단한 구현입니다.

with open('/etc/passwd', 'r') as f:
  try:
    f.seek(0,2)
    s = ''
    while s.count('\n') < 11:
      cur = f.tell()
      f.seek((cur - 10))
      s = f.read(10) + s
      f.seek((cur - 10))
    print s
  except Exception as e:
    f.readlines()

이를 가능하게 하는 매우 유용한 모듈이 있습니다.

from file_read_backwards import FileReadBackwards

with FileReadBackwards("/tmp/file", encoding="utf-8") as frb:

# getting lines by lines starting from the last line up
for l in frb:
    print(l)

A에서 제공한 답변에 대한 업데이트입니다.코디

python 3에서 동작합니다.

이것은 지수 검색을 사용하며 버퍼링만 합니다.N매우 효율적입니다.

import time
import os
import sys

def tail(f, n):
    assert n >= 0
    pos, lines = n+1, []

    # set file pointer to end

    f.seek(0, os.SEEK_END)

    isFileSmall = False

    while len(lines) <= n:
        try:
            f.seek(f.tell() - pos, os.SEEK_SET)
        except ValueError as e:
            # lines greater than file seeking size
            # seek to start
            f.seek(0,os.SEEK_SET)
            isFileSmall = True
        except IOError:
            print("Some problem reading/seeking the file")
            sys.exit(-1)
        finally:
            lines = f.readlines()
            if isFileSmall:
                break

        pos *= 2

    print(lines)

    return lines[-n:]




with open("stream_logs.txt") as f:
    while(True):
        time.sleep(0.5)
        print(tail(f,2))

파일의 마지막 줄에서 특정 값을 읽어야 했는데 우연히 이 스레드를 발견했습니다.Python에서 휠을 재창조하는 대신 /usr/local/bin/get_last_netp로 저장된 작은 셸 스크립트로 저장했습니다.

#! /bin/bash
tail -n1 /home/leif/projects/transfer/export.log | awk {'print $14'}

그리고 Python 프로그램에서는:

from subprocess import check_output

last_netp = int(check_output("/usr/local/bin/get_last_netp"))

디큐를 사용한 첫 번째 예가 아니라 더 단순한 것입니다.이것은 일반적인 것으로, 파일 뿐만이 아니라, 반복 가능한 오브젝트에서도 동작합니다.

#!/usr/bin/env python
import sys
import collections
def tail(iterable, N):
    deq = collections.deque()
    for thing in iterable:
        if len(deq) >= N:
            deq.popleft()
        deq.append(thing)
    for thing in deq:
        yield thing
if __name__ == '__main__':
    for line in tail(sys.stdin,10):
        sys.stdout.write(line)
This is my version of tailf

import sys, time, os

filename = 'path to file'

try:
    with open(filename) as f:
        size = os.path.getsize(filename)
        if size < 1024:
            s = size
        else:
            s = 999
        f.seek(-s, 2)
        l = f.read()
        print l
        while True:
            line = f.readline()
            if not line:
                time.sleep(1)
                continue
            print line
except IOError:
    pass
import time

attemps = 600
wait_sec = 5
fname = "YOUR_PATH"

with open(fname, "r") as f:
    where = f.tell()
    for i in range(attemps):
        line = f.readline()
        if not line:
            time.sleep(wait_sec)
            f.seek(where)
        else:
            print line, # already has newline
import itertools
fname = 'log.txt'
offset = 5
n = 10
with open(fname) as f:
    n_last_lines = list(reversed([x for x in itertools.islice(f, None)][-(offset+1):-(offset+n+1):-1]))
abc = "2018-06-16 04:45:18.68"
filename = "abc.txt"
with open(filename) as myFile:
    for num, line in enumerate(myFile, 1):
        if abc in line:
            lastline = num
print "last occurance of work at file is in "+str(lastline) 

다른 솔루션

txt 파일이 다음과 같은 경우: 쥐뱀 고양이 도마뱀 늑대개

python '의 배열 인덱싱을 사용하는 것만으로 이 파일을 되돌릴 수 있습니다.

contents=[]
def tail(contents,n):
    with open('file.txt') as file:
        for i in file.readlines():
            contents.append(i)

    for i in contents[:n:-1]:
        print(i)

tail(contents,-5)

결과: 개늑대 도마뱀 고양이

음! 나도 비슷한 문제가 있었는데 라스트라인만 필요해서 나름의 해결책을 생각해냈어.

def get_last_line(filepath):
    try:
        with open(filepath,'rb') as f:
            f.seek(-1,os.SEEK_END)
            text = [f.read(1)]
            while text[-1] != '\n'.encode('utf-8') or len(text)==1:
                f.seek(-2, os.SEEK_CUR)
                text.append(f.read(1))
    except Exception as e:
        pass
    return ''.join([t.decode('utf-8') for t in text[::-1]]).strip()

이 함수는 파일의 마지막 문자열을 반환합니다.
1.27GB의 로그파일이 있어 마지막 행을 찾는 데 걸리는 시간이 매우 짧습니다(반초도 걸리지 않습니다).

언급URL : https://stackoverflow.com/questions/136168/get-last-n-lines-of-a-file-similar-to-tail

반응형