Самый эффективный способ искать последние x строки файла в Python

Попробуйте сделать вместо этого:

pip install tobii-research

Как вы упоминали, Tobii Pro SDK позволяет вам легко взаимодействовать с вашим трекером и писать собственные исследовательские приложения для сбора и анализа глаз. данные отслеживания. Я рекомендую вам связаться напрямую с Tobii Pro Support , как указано в раннем посте . У вас также есть форум , они быстро вам ответят.

31
задан Harley Holcombe 3 November 2008 в 23:01
поделиться

15 ответов

# Tail
from __future__ import with_statement

find_str = "FIREFOX"                    # String to find
fname = "g:/autoIt/ActiveWin.log_2"     # File to check

with open(fname, "r") as f:
    f.seek (0, 2)           # Seek @ EOF
    fsize = f.tell()        # Get Size
    f.seek (max (fsize-1024, 0), 0) # Set pos @ last n chars
    lines = f.readlines()       # Read to end

lines = lines[-10:]    # Get last 10 lines

# This returns True if any line is exactly find_str + "\n"
print find_str + "\n" in lines

# If you're searching for a substring
for line in lines:
    if find_str in line:
        print True
        break
33
ответ дан 27 November 2019 в 21:34
поделиться

Я думаю, читая последних 2 КБ или таким образом, из файла должен удостовериться, что Вы получаете 10 строк и не должны быть слишком большим количеством пожирателя ресурсов.

file_handle = open("somefile")
file_size = file_handle.tell()
file_handle.seek(max(file_size - 2*1024, 0))

# this will get rid of trailing newlines, unlike readlines()
last_10 = file_handle.read().splitlines()[-10:]

assert len(last_10) == 10, "Only read %d lines" % len(last_10)
7
ответ дан 27 November 2019 в 21:34
поделиться

При выполнении Python в системе POSIX можно использовать 'хвост-10' для получения последних нескольких строк. Это может быть быстрее, чем написание Вашего собственного кода Python для получения последних 10 строк. Вместо того, чтобы открывать файл непосредственно, откройте канал от команды 'хвост-10 имен файла'. Если Вы уверены в выводе журнала, хотя (например, Вы знаете, что существует никогда любые очень длинные строки, которые являются сотнями или тысячами символов в длину), затем использование одного из 'чтения, последние 2 КБ' перечисленные подходы были бы прекрасны.

8
ответ дан 27 November 2019 в 21:34
поделиться

Вот ответ как MizardX, но без его очевидной проблемы занимания время в худшем случае от повторного сканирования добавляется рабочая строка неоднократно для новых строк как блоки.

По сравнению с activestate решением (который также, кажется, квадратичен), это не аварийно завершается, учитывая пустой файл и делает каждый ищет на чтение блока вместо два.

По сравнению с мечущим икру 'хвостом', это является автономным. (Но 'хвост' является лучшим, если у Вас есть он.)

По сравнению с захватом некоторых КБ от конца и надежды это достаточно, это работает на любую длину строки.

import os

def reversed_lines(file):
    "Generate the lines of file in reverse order."
    part = ''
    for block in reversed_blocks(file):
        for c in reversed(block):
            if c == '\n' and part:
                yield part[::-1]
                part = ''
            part += c
    if part: yield part[::-1]

def reversed_blocks(file, blocksize=4096):
    "Generate blocks of file's contents in reverse order."
    file.seek(0, os.SEEK_END)
    here = file.tell()
    while 0 < here:
        delta = min(blocksize, here)
        here -= delta
        file.seek(here, os.SEEK_SET)
        yield file.read(delta)

Для использования его согласно просьбе:

from itertools import islice

def check_last_10_lines(file, key):
    for line in islice(reversed_lines(file), 10):
        if line.rstrip('\n') == key:
            print 'FOUND'
            break

Редактирование: измененная карта () к itertools.imap () в голове (). Редактирование 2: упростил reversed_blocks (). Редактирование 3: избегают хвоста повторного сканирования для новых строк. Редактирование 4: переписал reversed_lines (), потому что str.splitlines () игнорирует финал '\n', поскольку замеченный BrianB (благодарит).

Примечание, которое в очень старом Python присваивает версию конкатенации строк в цикле здесь, займет время. CPython, по крайней мере, с последних нескольких лет избегает этой проблемы автоматически.

34
ответ дан 27 November 2019 в 21:34
поделиться

Вы могли считать блоки приблизительно 1 000 байтов от конца файла в буфер, пока у Вас нет 10 строк.

1
ответ дан 27 November 2019 в 21:34
поделиться

Это решение считает файл только однажды, но использование 2 указателей объекта файла для сможения получает последние строки N файла, не перечитывая его:

def getLastLines (path, n):
    # return the las N lines from the file indicated in path

    fp = open(path)
    for i in range(n):
        line = fp.readline()
        if line == '':
            return []

    back = open(path)
    for each in fp:
        back.readline()

    result = []
    for line in back:
        result.append(line[:-1])

    return result




s = "foo"
last_bit = getLastLines(r'C:\Documents and Settings\ricardo.m.reyes\My Documents\desarrollo\tail.py', 10)
for line in last_bit:
    if line == s:
        print "FOUND"
0
ответ дан 27 November 2019 в 21:34
поделиться

Лично я испытал бы желание вспыхнуть к оболочке и хвосту вызова-n10 для загрузки файла. Но затем я не действительно Python программист ;)

0
ответ дан 27 November 2019 в 21:34
поделиться

Во-первых, функция, которая возвращает список:

def lastNLines(file, N=10, chunksize=1024):
    lines = None
    file.seek(0,2) # go to eof
    size = file.tell()
    for pos in xrange(chunksize,size-1,chunksize):
        # read a chunk
        file.seek(pos,2)
        chunk = file.read(chunksize)
        if lines is None:
            # first time
            lines = chunk.splitlines()
        else:
            # other times, update the 'first' line with
            # the new data, and re-split
            lines[0:1] = (chunk + lines[0]).splitlines()
        if len(lines) > N:
            return lines[-N:]
    file.seek(0)
    chunk = file.read(size-pos)
    lines[0:1] = (chunk + lines[0]).splitlines()
    return lines[-N:]
115-секундный, функция, которая выполняет итерации по строкам в обратном порядке:

def iter_lines_reversed(file, chunksize=1024):
    file.seek(0,2)
    size = file.tell()
    last_line = ""
    for pos in xrange(chunksize,size-1,chunksize):
        # read a chunk
        file.seek(pos,2)
        chunk = file.read(chunksize) + last_line
        # split into lines
        lines = chunk.splitlines()
        last_line = lines[0]
        # iterate in reverse order
        for index,line in enumerate(reversed(lines)):
            if index > 0:
                yield line
    # handle the remaining data at the beginning of the file
    file.seek(0)
    chunk = file.read(size-pos) + last_line
    lines = chunk.splitlines()
    for line in reversed(lines):
        yield line

Для Вашего примера:

s = "foo"
for index, line in enumerate(iter_lines_reversed(fileObj)):
    if line == s:
        print "FOUND"
        break
    elif index+1 >= 10:
        break

Редактирование: Теперь получает размер файла автоматически
Edit2: Теперь только выполняет итерации для 10 строк.

0
ответ дан 27 November 2019 в 21:34
поделиться

считайте последние несколько Ks файла и разделите это на строки для возврата только последних 10.

это довольно маловероятно запуск того блока для падения на границу строки, но Вы отбросите первые строки так или иначе.

0
ответ дан 27 November 2019 в 21:34
поделиться

Вы могли также считать строки, поскольку Вы инвертируете через файл, вместо того, чтобы предположить байтовое смещение.

lines = 0
chunk_size = 1024

f = file('filename')
f.seek(0, 2)
f.seek(f.tell() - chunk_size)

while True:
    s = f.read(chunk_size)
    lines += s.count('\n')
    if lines > NUM_OF_LINES:
        break
    f.seek(f.tell() - chunk_size*2)

Теперь файл в хорошем положении для выполнения readlines(). Вы также могли кэшировать строки, которые Вы читаете в первый раз, для устранения чтения той же части файла дважды.

1
ответ дан 27 November 2019 в 21:34
поделиться

Я столкнулся с той проблемой, анализируя в последний час БОЛЬШИХ файлов системного журнала, и использовал эту функцию от сайта рецепта activestate... ( http://code.activestate.com/recipes/439045/ )

!/usr/bin/env python
# -*-mode: python; coding: iso-8859-1 -*-
#
# Copyright (c) Peter Astrand <astrand@cendio.se>

import os
import string

class BackwardsReader:
    """Read a file line by line, backwards"""
    BLKSIZE = 4096

    def readline(self):
        while 1:
            newline_pos = string.rfind(self.buf, "\n")
            pos = self.file.tell()
            if newline_pos != -1:
                # Found a newline
                line = self.buf[newline_pos+1:]
                self.buf = self.buf[:newline_pos]
                if pos != 0 or newline_pos != 0 or self.trailing_newline:
                    line += "\n"
                return line
            else:
                if pos == 0:
                    # Start-of-file
                    return ""
                else:
                    # Need to fill buffer
                    toread = min(self.BLKSIZE, pos)
                    self.file.seek(-toread, 1)
                    self.buf = self.file.read(toread) + self.buf
                    self.file.seek(-toread, 1)
                    if pos - toread == 0:
                        self.buf = "\n" + self.buf

    def __init__(self, file):
        self.file = file
        self.buf = ""
        self.file.seek(-1, 2)
        self.trailing_newline = 0
        lastchar = self.file.read(1)
        if lastchar == "\n":
            self.trailing_newline = 1
            self.file.seek(-1, 2)

# Example usage
br = BackwardsReader(open('bar'))

while 1:
    line = br.readline()
    if not line:
        break
    print repr(line)

Это работает действительно хорошо и намного более эффективно затем что-либо как fileObj.readlines () [-10:], который заставляет Python считать весь файл в память и затем обрубает последние десять строк его.

2
ответ дан 27 November 2019 в 21:34
поделиться

Если Вы будете на поле Unix, [то 110], вероятно, будет самый быстрый путь. Иначе это зависит от того, как устойчивый Вы хотите, чтобы это было. Методы, предложенные до сих пор, будут все падать, так или иначе. Для устойчивости и скорости в наиболее распространенном случае Вы, вероятно, хотите что-то как логарифмический поиск: используйте file.seek, чтобы перейти к концу файла минус 1 000 символов, считать его в, проверить, сколько строк он содержит, затем к EOF минус 3 000 символов, считайте в 2000 символы, считайте строки, затем EOF минус 7000, читайте в 4 000 символов, считайте строки, и т.д. пока у Вас нет стольких строк, сколько Вам нужно. Но если Вы знаете наверняка, что это всегда будет работавшим файлы с разумными длинами строки, Вам, возможно, не понадобится это.

Вы могли бы также найти некоторое вдохновение в исходный код для команды unix tail.

2
ответ дан 27 November 2019 в 21:34
поделиться

Я думаю, что не забываю адаптировать код от это сообщение в блоге от Manu Garg , когда я должен был сделать что-то подобное.

2
ответ дан 27 November 2019 в 21:34
поделиться

Вот версия с помощью mmap, который кажется довольно эффективным. Большое плюс - то, что mmap автоматически обработает файл к требованиям подкачки страниц памяти для Вас.

import os
from mmap import mmap

def lastn(filename, n):
    # open the file and mmap it
    f = open(filename, 'r+')
    m = mmap(f.fileno(), os.path.getsize(f.name))

    nlcount = 0
    i = m.size() - 1 
    if m[i] == '\n': n += 1
    while nlcount < n and i > 0:
        if m[i] == '\n': nlcount += 1
        i -= 1
    if i > 0: i += 2

    return m[i:].splitlines()

target = "target string"
print [l for l in lastn('somefile', 10) if l == target]
5
ответ дан 27 November 2019 в 21:34
поделиться

Может быть, это может быть полезно:

import os.path

path = 'path_to_file'
os.system('tail -n1 ' + path)
0
ответ дан 27 November 2019 в 21:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: