2009-09-15 5 views
11

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

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

+0

http://stackoverflow.com/questions/915926/perl-read-new-records-added-to-a-file/915989#915989 – innaM

ответ

2

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

+1

Можете ли вы уточнить? –

22

В 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 
} 
+0

Да, работает то же самое в Python (или C, если на то пошло ;-). –

+0

Справа. искать и рассказывать - это только функции библиотеки файловой системы. Они будут делать то же самое на любом языке, который есть у них. – mob

+1

Будут ли проблемы с буферизацией? Должен ли быть изменен '$ |'? –

-1

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

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

Не знаете, почему я получил отрицательные голоса. – nosklo

+8

Мое предположение: вы не в тему. Заявитель попросил пример Perl. Вы отправили пример python. Следовательно, неудача. – Hawk

0

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

8

В 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

Что есть в callback sub для IO :: Tail? – Space

1

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

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

Смежные вопросы