2009-09-15 11 views
11

Recibo una secuencia de datos (formato de texto) de un servidor externo y me gusta pasarlos a una secuencia de comandos línea por línea. El archivo se adjunta de manera continua. ¿Cuál es el método ideal para realizar esta operación? ¿Sería útil el método IO :: Socket con Perl? Finalmente, estos datos tienen que pasar por un programa PHP (reutilizable) y finalmente aterrizar en una base de datos MySQL.¿Cómo leo un archivo que se actualiza constantemente?

La pregunta es cómo abrir el archivo, que continuamente se actualiza?

+0

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

Respuesta

2

Quizás un named pipe te ayude?

+1

¿Puede ser más específico? –

22

En Perl, puede hacer uso de seek y tell para leer desde un archivo en continuo crecimiento. Podría ser algo como esto (prestado liberalmente de 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í, funciona igual en Python (o C, para el caso ;-). –

+0

Derecha. Buscar y contar son solo funciones de la biblioteca del sistema de archivos. Harán lo mismo en cualquier idioma que los tenga. – mob

+1

¿Habrá problemas de almacenamiento en búfer? ¿Debe '$ |' ser modificado? –

-1

en Python es bastante recta hacia adelante:

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

No estoy seguro de por qué obtuve votos negativos. – nosklo

+8

Supongo que estás fuera del tema. El solicitante pidió un ejemplo de Perl. Publicaste un ejemplo de Python. De ahí el fracaso. – Hawk

0

Las soluciones para leer toda la multa a buscar hasta el final son perfomance- imprudente. Si eso ocurre en Linux, sugeriría simplemente cambiar el nombre del archivo de registro. Luego, puede escanear todas las entidades en el archivo renombrado, mientras que aquellas en el archivo original se llenarán nuevamente. Después de escanear todo el archivo renombrado, elimínelo. O muévete donde quieras. De esta forma obtienes algo así como logrotate pero para escanear datos recién llegados.

8

En perl hay un par de módulos que hacen que rastrear un archivo sea más fácil. IO::Tail y File::Tail uno usa una devolución de llamada, el otro usa una lectura de bloqueo por lo que solo depende de lo que se ajuste mejor a sus necesidades. También hay otros módulos de seguimiento, pero estos son los dos que me vinieron a la mente.

IO::Tail - siga la cola de archivos/corriente

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

File::Tail - extensión Perl para la lectura de los archivos actualizados continuamente

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

¿Qué hay en el sub de devolución de llamada para IO :: Tail? – Space

1

Usted habla de abrir un archivo, y preguntar acerca de IO::Socket. Estas no son exactamente las mismas cosas, incluso si en el fondo vas a leer los datos de un descriptor de archivo.

Si puede acceder a la transmisión remota desde una tubería con nombre o FIFO, entonces puede simplemente abrirlo como un archivo ordinario. Bloqueará cuando no haya nada disponible y regresará siempre que haya datos que deban drenarse. Puede, o no, tener que llevar File::Tail para abordar el problema de no perder datos si el remitente corre demasiado lejos de usted.

Por otro lado, si abre un socket directamente al otro servidor (lo que parece más probable), IO::Socket no funcionará de la caja, ya que no hay un método getline disponible. Tendría que leer y almacenar el bloque por bloque y distribuirlo línea por línea a través de un marcador intermedio.

Puede extraer el descriptor de socket en un IO::Handle, y usar getline() en eso.Algo así como:

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 
} 

Puede que tenga que realizar un apretón de manos con el fin de iniciar la recepción de paquetes, pero eso es otro asunto.

Cuestiones relacionadas