احصل على الأسطر n الأخيرة من الملف باستخدام Python، على غرار الذيل

StackOverflow https://stackoverflow.com/questions/136168

سؤال

أنا أكتب عارض ملف سجل لتطبيق ويب ولهذا أريد أن أقوم بترقيم الصفحات عبر أسطر ملف السجل.العناصر الموجودة في الملف مبنية على سطر مع العنصر الأحدث في الأسفل.

لذلك أنا بحاجة إلى 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

هل هذا هو النهج المعقول؟ما هي الطريقة الموصى بها لربط ملفات السجل بالإزاحات؟

هل كانت مفيدة؟

المحلول 6

الكود الذي انتهى بي الأمر باستخدامه.أعتقد أن هذا هو الأفضل حتى الآن:

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

نصائح أخرى

قد يكون هذا أسرع من لك.لا يقدم أي افتراضات حول طول الخط.يتم الرجوع إلى الملف كتلة تلو الأخرى حتى يتم العثور على العدد الصحيح من الأحرف ' '.

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 سطرًا على الفور تقريبًا.

كما أنني لا أحرق الكثير من السعرات الحرارية في الدماغ أثناء محاولتي تحسين المواءمة مع كتل نظام التشغيل الفعلية.باستخدام حزم الإدخال/الإخراج عالية المستوى هذه، أشك في أنك سترى أي نتيجة أداء لمحاولة التوافق مع حدود كتلة نظام التشغيل.إذا كنت تستخدم الإدخال/الإخراج ذي المستوى الأدنى، فقد ترى تسريعًا.

بافتراض وجود نظام يشبه يونكس على Python 2، يمكنك القيام بما يلي:

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]

بالنسبة لبيثون 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]

إذا كانت قراءة الملف بأكمله مقبولة، فاستخدم deque.

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

قبل الإصدار 2.6، لم يكن لدى deques خيار 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

إذا كان من الضروري قراءة الملف من النهاية، فاستخدم البحث السريع (المعروف أيضًا باسم الأسي).

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

هنا جوابي.بيثون خالص.باستخدام الوقت يبدو سريعًا جدًا.ذيل 100 سطر من ملف السجل الذي يحتوي على 100000 سطر:

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

إجابة S.Lott أعلاه تناسبني تقريبًا ولكنها في النهاية تعطيني خطوطًا جزئية.اتضح أنه يفسد البيانات الموجودة على حدود الكتل لأن البيانات تحتفظ بكتل القراءة بترتيب عكسي.عند استدعاء ''.join(data)، تكون الكتل بترتيب خاطئ.هذا يصلح ذلك.

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

حل بسيط وسريع مع 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()

إصدار متوافق مع 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')

لقد وجدت أن Popen أعلاه هو الحل الأفضل.إنه سريع وقذر ويعمل مع Python 2.6 على جهاز UNIX ، استخدمت ما يلي

    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

سوف يحتوي الإخراج على الأسطر n الأخيرة من الكود.للتكرار من خلال خط الإخراج سطرًا تلو الآخر قم بما يلي:

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

قم بتحديث حل @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:]

نشر إجابة بناء على طلب من المعلقين على إجابتي على سؤال مماثل حيث تم استخدام نفس التقنية لتغيير السطر الأخير من الملف، وليس الحصول عليه فقط.

بالنسبة للملف ذو الحجم الكبير، mmap هي أفضل طريقة للقيام بذلك.لتحسين الموجود mmap الإجابة، هذا الإصدار محمول بين Windows وLinux، ويجب أن يعمل بشكل أسرع (على الرغم من أنه لن يعمل بدون بعض التعديلات على Python 32 بت مع ملفات في نطاق GB، راجع إجابة أخرى للحصول على تلميحات حول التعامل مع هذا، ولتعديله للعمل على 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

ملحوظة:لقد قمت بكتابة كل هذا على جهاز لا أستطيع الوصول إلى لغة بايثون لاختباره.يرجى إعلامي إذا كتبت أي شيء؛كان هذا مشابهًا بدرجة كافية لـ إجابتي الأخرى أنني يفكر يجب أن تعمل، ولكن القرص (على سبيل المثال.التعامل مع offset) يمكن أن يؤدي إلى أخطاء طفيفة.واسمحوا لي أن أعرف في التعليقات إذا كان هناك أي أخطاء.

بناءً على أفضل إجابة لـ S.Lott (25 سبتمبر 2008 الساعة 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 على pypi والتي يمكنك تثبيتها باستخدام النقطة:

  • mtFileUtil
  • متعدد الذيل
  • com.log4tailer
  • ...

اعتمادًا على حالتك، قد تكون هناك مزايا لاستخدام إحدى هذه الأدوات الموجودة.

إليك تنفيذ بسيط جدًا:

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

بسيط :

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

لتحقيق الكفاءة مع الملفات الكبيرة جدًا (شائعة في مواقف ملفات السجل حيث قد ترغب في استخدام الذيل)، فأنت تريد عمومًا تجنب قراءة الملف بأكمله (حتى إذا قمت بذلك دون قراءة الملف بأكمله في الذاكرة مرة واحدة) ومع ذلك، يمكنك القيام بذلك بحاجة إلى العمل بطريقة أو بأخرى على الإزاحة في الأسطر بدلاً من الأحرف.أحد الاحتمالات هو القراءة بشكل عكسي باستخدام See() char تلو 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

[تحرير] تمت إضافة إصدار أكثر تحديدًا (يتجنب الحاجة إلى الرجوع مرتين)

يمكنك الانتقال إلى نهاية ملفك باستخدام 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 (10 يونيو 2010 الساعة 21:28):تضيف هذه الفئة أسلوب الرأس () والذيل () إلى كائن الملف.

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)

تواجه العديد من هذه الحلول مشكلات إذا لم ينتهي الملف بـ أو في ضمان قراءة السطر الأول بالكامل.

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

اضطررت لقراءة قيمة محددة من السطر الأخير من الملف، وعثرت على هذا الموضوع.بدلاً من إعادة اختراع العجلة في بيثون ، انتهى بي الأمر بنصوص قذيفة صغيرة ، تم حفظها كـ/usr/local/bin/get_last_netp:

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

وفي برنامج بايثون:

from subprocess import check_output

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

ليس المثال الأول الذي يستخدم deque، ولكنه أبسط.وهذا عام:فهو يعمل على أي كائن قابل للتكرار، وليس مجرد ملف.

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

هناك مفيدة جدا وحدة التي يمكن أن تفعل هذا:

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)

بعد التفكير مرة أخرى، من المحتمل أن يكون هذا بنفس سرعة أي شيء هنا.

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]

إنه أبسط بكثير.ويبدو أنها تمزق بوتيرة جيدة.

لقد وجدت الطريقة الأسهل للعثور على الأسطر N الأولى أو الأخيرة من الملف

آخر N أسطر من الملف (على سبيل المثال: N = 10)

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

الأسطر N الأولى من الملف (على سبيل المثال: N = 10)

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

في غاية البساطة:

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

على الرغم من أن هذا ليس في الجانب الفعال مع الملفات الكبيرة، إلا أن هذا الكود واضح جدًا:

  1. يقرأ كائن الملف، f.
  2. يقوم بتقسيم السلسلة التي تم إرجاعها باستخدام الأسطر الجديدة، \n.
  3. يحصل على المصفوفة التي تسرد الفهارس الأخيرة، باستخدام الإشارة السالبة للإشارة إلى الفهارس الأخيرة، و : للحصول على صفيف فرعي.

    def tail(f,n):
        return "\n".join(f.read().split("\n")[-n:])
    
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top