Как читать файл, который постоянно обновляется?

Я получаю поток данных (текстовый формат) с внешнего сервера и хотел бы передать его в script по очереди. Файл добавляется в непрерывном режиме. Это идеальный метод для выполнения этой операции. Будет ли использоваться метод IO:: Socket с использованием Perl? В конце концов, эти данные должны проходить через программу PHP (многократно использовать) и, в конечном итоге, попадать в базу данных MySQL.

Вопрос заключается в том, как открыть файл, который постоянно обновляется?

Ответ 1

В Perl вы можете использовать seek и tell, чтобы читать из постоянно растущего файла. Это может выглядеть примерно так (заимствовано либерально из perldoc -f seek)

open(FH,'<',$the_file) || handle_error();  # typical open call
for (;;) {
    while (<FH>) {
        # ... process $_ and do something with it ...
    }
    # eof reached on FH, but wait a second and maybe there will be more output
    sleep 1;
    seek FH, 0, 1;      # this clears the eof flag on FH
}

Ответ 2

В perl есть несколько модулей, которые упрощают обработку файла. IO:: Tail и File:: Tail используется обратный вызов, другой использует блокировку, чтобы он просто зависел от того, что лучше подходит вашим потребностям. Вероятно, есть и другие хвостовые модули, но это те, которые приходят на ум.

IO:: Tail - следовать хвосту файлов/потоков

 use IO::Tail;
 my $tail = IO::Tail->new();
 $tail->add('test.log', \&callback);
 $tail->check();
 $tail->loop();

File:: Tail - расширение Perl для чтения из постоянно обновляемых файлов

use File::Tail;
my $file = File::Tail->new("/some/log/file");
while (defined(my $line= $file->read)) {
    print $line;
}

Ответ 3

Возможно, вам поможет named pipe?

Ответ 4

Вы говорите об открытии файла и спрашиваете о IO::Socket. Это не совсем то же самое, даже если вы глубоко читаете данные дескриптора файла.

Если вы можете получить доступ к удаленному потоку из именованного канала или FIFO, вы можете просто открыть его как обычный файл. Он будет блокироваться, когда ничего не будет доступно, и возвращаться всякий раз, когда есть данные, которые необходимо удалить. Вы можете или, возможно, не должны приносить File::Tail для решения проблемы потери данных, если отправитель слишком сильно опережает вас.

С другой стороны, если вы открываете сокет непосредственно на другой сервер (что кажется более вероятным), IO::Socket не будет работать из коробки, так как нет метода getline. Вам нужно будет читать и буферизировать блок-за-блоком, а затем выполнять его по очереди через промежуточное удерживающее перо.

Вы можете вывести дескриптор сокета в IO::Handle и использовать getline(). Что-то вроде:

my $sock = IO::Socket::INET->new(
    PeerAddr => '172.0.0.1',
    PeerPort => 1337,
    Proto    => 'tcp'
) or die $!;

my $io = new IO::Handle;
$io->fdopen(fileno($sock),"r") or die $!;

while (defined( my $data = $io->getline() )) {
    chomp $data;
    # do something
}

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

Ответ 5

Решения для чтения всего штрафа, направленные на достижение цели, - это исполнение - неразумное. Если это произойдет в Linux, я бы предложил просто переименовать файл журнала. Затем вы можете отсканировать все entites в переименованном файле, в то время как в исходном файле снова будет заполнено. После сканирования всего переименованного файла - удалите его. Или двигайся, когда хочешь. Таким образом, вы получаете что-то вроде logrotate, но для сканирования вновь прибывающих данных.

Ответ 6

В python это довольно прямолинейно:

f = open('teste.txt', 'r')
for line in f: # read all lines already in the file
    print line.strip()

# keep waiting forever for more lines.
while True:
    line = f.readline() # just read more
    if line: # if you got something...
        print 'got data:', line.strip()
    time.sleep(1) # wait a second to not fry the CPU needlessy