Как мне прочитать файл, который постоянно обновляется? - PullRequest
14 голосов
/ 15 сентября 2009

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

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

Ответы [ 6 ]

24 голосов
/ 15 сентября 2009

В 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
}
9 голосов
/ 15 сентября 2009

В 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;
}
2 голосов
/ 15 сентября 2009

Возможно, именованная труба поможет вам?

1 голос
/ 15 сентября 2009

Вы говорите об открытии файла и спрашиваете о 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
}

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

0 голосов
/ 15 сентября 2009

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

0 голосов
/ 15 сентября 2009

В питоне это довольно просто:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...