Как читать файл, который постоянно обновляется?
Я получаю поток данных (текстовый формат) с внешнего сервера и хотел бы передать его в 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