Frage

Ich schreibe einen Log-Datei-Viewer für eine Web-Anwendung und für das ich will durch die Zeilen der Protokolldatei Paginieren. Die Elemente in der Datei werden entsprechend dem neuesten Artikel auf der Unterseite basiert.

Also brauche ich eine Methode, die tail() n Linien von unten lesen können und unterstützt einen Offset. Was ich kam mit sieht wie folgt aus:

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

Ist das ein sinnvoller Ansatz? Was ist der empfohlene Weg, um tail-Log-Dateien mit Offsets?

War es hilfreich?

Lösung 6

Der Code, den ich am Ende mit. Ich denke, dies ist die beste bisher:

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

Andere Tipps

Dies kann schneller sein als Ihre. Macht keine Annahmen über Leitungslänge. Sichere durch die Datei eines Block zu einer Zeit, bis es die richtige Anzahl von ‚\ n‘ Zeichen gefunden wird.

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:])

Ich mag es nicht heikel Annahmen über Leitungslänge, wenn - wie eine praktische Sache - man kann nie Dinge wie das wissen kann,

.

Im Allgemeinen wird dies die letzten 20 Zeilen auf dem ersten oder zweiten Durchlauf durch die Schleife lokalisieren. Wenn Ihr 74 Zeichen, was eigentlich genau ist, machen Sie die Blockgröße 2048 und Sie werden tail 20 Zeilen fast sofort.

Auch ich nicht viel Gehirn Kalorien verbrennen versucht Ausrichtung mit physischen OS Blöcke Finesse. Mit diesen High-Level-I / O-Paketen, bezweifle ich Dir jede Leistung Folge sehen werden versuchen, auf O Blockgrenzen auszurichten. Wenn Sie auf niedrigerer Ebene verwenden I / O, dann könnten Sie eine Speedup sehen.

Vorausgesetzt wird ein Unix-ähnliches System auf Python 2 Sie tun können:

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]

Für 3 Python können Sie tun:

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]

Wenn Sie die gesamte Datei zu lesen akzeptabel, dann ist eine deque verwenden.

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

Vor 2.6 deques haben keine maxlen Option, aber es ist einfach genug, um zu implementieren.

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

Wenn es eine Anforderung, die Datei aus dem Ende zu lesen, dann einen Galopp verwenden (a.k.a exponentiell) suchen.

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:]

Hier ist meine Antwort. Reiner Python. Mit timeit scheint es ziemlich schnell. Tailing 100 Zeilen einer Protokolldatei, die 100.000 Zeilen hat:

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

Hier ist der Code:

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:]

S.Lott Antwort über fast funktioniert für mich aber endet mir Teillinien geben. Es stellt sich heraus, dass es Daten über Blockgrenzen korrumpiert, weil Daten, die die Leseblocks in umgekehrter Reihenfolge halten. Wenn ‚‘ .join (data) bezeichnet wird, werden die Blöcke in der falschen Reihenfolge. Dies behebt das.

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:]

Einfache und schnelle Lösung mit 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()

Eine noch sauberere python3 kompatible Version, die einfügen nicht, sondern fügt & umkehrt:

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:])

verwenden Sie es wie folgt aus:

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

Ich fand die Popen über die beste Lösung zu sein. Es ist schnell und schmutzig und es funktioniert Für Python 2.6 auf Unix-Rechner habe ich die folgenden

    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

soutput wird letzten n Zeilen des Codes enthalten haben. durch soutput Linie iterieren Zeile tun:

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

Update @papercrane Lösung python3. Öffnen Sie die Datei mit open(filename, 'rb') und:

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:]

Posting eine Antwort auf Geheiß von commenters auf meine Antwort auf eine ähnliche Frage wo die gleiche Technik verwendet wurde, die letzte Zeile einer Datei zu mutieren, nicht nur es.

Für eine Datei von signifikanter Größe, mmap ist der beste Weg, um mach das. Zur Verbesserung der bestehenden mmap Antwort, diese Version ist portabel zwischen Windows und Linux und soll schneller laufen (obwohl es nicht ohne Modifikationen auf 32-Bit-Python mit Dateien im GB-Bereich arbeitet, finden Sie in die andere Antwort für Hinweise auf das Handling und zur Modifizierung auf Python 2 ) zu arbeiten.

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)

Dies setzt voraus, die Anzahl der Zeilen ist tailed klein genug, um Sie sicher, sie alle in dem Speicher auf einmal lesen können; Sie könnte auch dies eine Generatorfunktion machen und manuell eine Zeile zu einem Zeitpunkt durch die letzte Zeile zu ersetzen mit lesen:

        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)

Schließlich diese Lese im Binär-Modus (notwendig zu verwenden mmap), so gibt es str Linien (Py2) und bytes Linien (PY3); wenn Sie unicode (Py2) oder str (PY3) wollen, könnte der iterativen Ansatz optimiert werden für Sie zu entschlüsseln und / oder zu beheben Zeilenumbrüche:

        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

Hinweis: Ich tippte das alles auf einer Maschine, wo ich Zugriff auf Python Test fehlt. Bitte lassen Sie mich wissen, ob ich etwas typoed; Das war genug, um ähnliche href="/a/33811809/364696"> meine andere Antwort denken es sollte funktionieren, aber die Verbesserungen (zB eine offset Handling) könnte dazu führen, auf subtile Fehler. Bitte lassen Sie mich in den Kommentaren wissen, ob es irgendwelche Fehler.

basierend auf S.Lott Top gestimmt Antwort (25. September '08 um 21:43 Uhr), aber für kleine Dateien festgelegt.

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

Hope dies sinnvoll ist.

Es gibt einige bestehende Implementierungen von Schwanz auf pypi, die Sie installieren können, pip mit:

  • mtFileUtil
  • multitail
  • log4tailer
  • ...

Je nach Ihrer Situation, kann es von Vorteil sein, eine dieser vorhandenen Werkzeuge zu verwenden.

Hier ist eine ziemlich einfache Implementierung:

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

Ganz einfach:

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

Für Effizienz mit sehr großen Dateien (häufig in Logfile Situationen, in denen Sie verwenden Schwanz mögen), können Sie im Allgemeinen zu vermeiden, wollen die gesamte Datei zu lesen (auch wenn Sie es tun, tun, ohne die gesamte Datei in dem Speicher auf einmal lesen) jedoch , müssen Sie irgendwie in den Zeilen der Versatz arbeiten, anstatt Zeichen. Eine Möglichkeit ist das Lesen rückwärts mit seek () char von char, aber das ist sehr langsam. Stattdessen ist es besser, in größeren Blöcken zu verarbeiten.

Ich habe eine Nutzenfunktion mich vor einer Weile geschrieben Dateien rückwärts zu lesen, die hier verwendet werden kann.

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

[Bearbeiten] Hinzugefügt speziellere Version (Vermeidet müssen zweimal rückwärts)

Sie bis zum Ende Ihrer Datei mit f.seek gehen können (0, 2) und dann abgelesen Zeilen nacheinander mit dem folgenden Ersatz für 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

Basierend auf Eyecue Antwort (10. Juni '10 um 21:28 Uhr.): Diese Klasse hinzufügen Kopf () und Schwanz () -Methode Objekt in Datei

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:]

Verbrauch:

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

Einige dieser Lösungen haben Probleme, wenn die Datei nicht in \ n endet oder in die komplette erste Zeile sichergestellt gelesen wird.

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

Ich hatte einen bestimmten Wert aus der letzten Zeile einer Datei zu lesen, und auf diesem Thread gestolpert. Anstatt das Rad neu zu erfinden, in Python, landete ich mit einem kleinen Shell-Skript auf, gespeichert als / Usr / local / bin / get_last_netp:

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

Und im Python-Programm:

from subprocess import check_output

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

Nicht das erste Beispiel eine deque verwenden, aber ein einfacheres. Dies ist allgemein:. Es funktioniert auf jedem iterable Objekt, nicht nur eine Datei

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

Es ist sehr nützlich, Modul die dies tun können:

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)

Am zweiten Gedanken, das ist wahrscheinlich genauso schnell wie alles hier.

def tail( f, window=20 ):
    lines= ['']*window
    count= 0
    for l in f:
        lines[count%window]= l
        count += 1
    print lines[count%window:], lines[:count%window]

Es ist viel einfacher. Und es scheint in einem guten Tempo zu zerreißen entlang.

fand ich eine wahrscheinlich der einfachste Weg, um die ersten oder letzten N Zeilen einer Datei finden

Letzte N Zeilen einer Datei (Ex: N = 10)

file=open("xyz.txt",'r")
liner=file.readlines()
for ran in range((len(liner)-N),len(liner)):
    print liner[ran]

Erste N Zeilen einer Datei (Ex: N = 10)

file=open("xyz.txt",'r")
liner=file.readlines()
for ran in range(0,N+1):
    print liner[ran]

Es ist so einfach:

def tail(fname,nl):
with open(fname) as f:
    data=f.readlines() #readlines return a list
    print(''.join(data[-nl:]))

Obwohl dies auf der effizienten Seite mit großen Dateien nicht wirklich ist, dieser Code ist ziemlich geradlinig:

  1. Es liest das Dateiobjekt, f.
  2. Sie spaltet die Zeichenfolge Zeilenumbrüche zurück verwenden, \n.
  3. Es wird die Array-Listen letzte Indizes, das negative Vorzeichen mit dem letzten Indizes steht, und die : ein Sub-Array zu erhalten.

    def tail(f,n):
        return "\n".join(f.read().split("\n")[-n:])
    
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top