2009-09-15 16 views
11

Ricevo un flusso di dati (formato testo) da un server esterno e mi piace trasmetterlo a uno script riga per riga. Il file viene accodato in modo continuo. Qual è il metodo ideale per eseguire questa operazione. Lo farà il metodo IO :: Socket usando Perl? Alla fine, questi dati devono passare attraverso un programma PHP (riutilizzabile) ed eventualmente finire su un database MySQL.Come si legge un file che si aggiorna costantemente?

La domanda è come aprire il file, che viene continuamente aggiornato?

+0

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

risposta

2

Forse uno named pipe ti può aiutare?

+1

Puoi essere più specifico? –

22

In Perl, è possibile utilizzare seek e tell per leggere da un file in continua crescita. Potrebbe essere simile a questa (preso in prestito liberalmente da 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

Sì, funziona allo stesso modo in Python (o C, per quello ;-). –

+0

Giusto. cercare e raccontare sono solo funzioni della libreria del file system. Faranno la stessa cosa in qualsiasi lingua che li abbia. – mob

+1

Ci saranno problemi di buffering? Dovrebbe essere '$ |' modificato? –

-1

in Python è piuttosto straight-forward:

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

Non so perché ho ottenuto voti negativi. – nosklo

+8

La mia ipotesi sarebbe che sei fuori tema. Il richiedente ha chiesto un esempio Perl. Hai pubblicato un esempio python. Da qui il fallimento. – Hawk

0

Le soluzioni di leggere l'intero fine per cercare di fine sono perfomance- imprudente. Se ciò accade sotto Linux, suggerirei semplicemente di rinominare il file di registro. Quindi, è possibile eseguire la scansione di tutte le entrate nel file rinominato, mentre quelle nel file originale verranno nuovamente riempite. Dopo aver eseguito la scansione di tutto il file rinominato, cancellarlo. O spostati dove vuoi. In questo modo si ottiene qualcosa come logrotate, ma per la scansione di nuovi dati in arrivo.

8

In perl ci sono un paio di moduli che rendono più agevole la coda di un file. IO::Tail e File::Tail uno usa un callback, l'altro usa una lettura bloccante, quindi dipende solo da quale si adatta meglio alle tue esigenze. Probabilmente ci sono anche altri moduli tailing ma questi sono i due che mi vengono in mente.

IO::Tail - seguire la coda di file/flusso

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

File::Tail - estensione Perl per la lettura da file continuamente aggiornati

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

Cosa c'è nel sottotitolo di callback per IO :: Tail? – Space

1

Lei parla di apertura di un file, e chiedere informazioni IO::Socket. Queste non sono esattamente le stesse cose, anche se in fondo leggerai i dati di un descrittore di file.

Se è possibile accedere allo stream remoto da una named pipe o FIFO, è sufficiente aprirlo come un file normale. Bloccherà quando nulla è disponibile, e ritornerà ogni volta che ci sono dati che devono essere svuotati. È possibile, o meno, dover portare File::Tail a sopportare il problema di non perdere dati se il mittente è troppo avanti.

D'altra parte, se si sta aprendo un socket direttamente all'altro server (che sembra più probabile), IO::Socket non funzionerà correttamente poiché non è disponibile il metodo getline. Dovresti leggere e bufferare blocco per blocco e poi distribuirlo riga per riga attraverso una penna intermedia.

È possibile estrarre il descrittore di socket in un IO::Handle e utilizzare getline() su quello.Qualcosa di simile:

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 
} 

Potrebbe essere necessario eseguire una stretta di mano, al fine di iniziare a ricevere i pacchetti, ma questa è un'altra questione.

Problemi correlati