2011-12-18 8 views
7

¿Hay alguna forma rápida y eficiente de leer líneas específicas de archivos grandes, sin cargarlos en la memoria?Lectura de una línea específica de un archivo grande en Perl

Escribí una secuencia de comandos perl, que ejecuta muchas bifurcaciones y me gustaría que leyeran líneas específicas de un archivo.

Por el momento estoy usando un comando externo:

sub getFileLine { 
    my ($filePath, $lineWanted) = @_; 
    $SIG{PIPE} = '_IGNORE_'; 
    open(my $fh, '-|:utf8', "tail -q -n +$lineWanted \"$filePath\" | head -n 1"); 
    my $line = <$fh>; 
    close $fh; 
    chomp($line); 
    return $line; 
} 

Su rápido y funciona - pero tal vez hay una manera más "Perl-ish", lo más rápido y eficiente de la memoria como ésta?

Como sabes, la creación de un proceso de horquilla en Perl duplica la memoria de proceso principal, por lo que si el proceso principal usa 10 MB, la horquilla utilizará al menos esa cantidad.

Mi objetivo es mantener el proceso de horquilla (por lo que el proceso principal hasta que las horquillas se ejecutan también) uso de la memoria lo más bajo posible. Es por eso que no quiero cargar todo el archivo en la memoria.

+2

por cierto, es 'IGNORE', no' _IGNORE_'. – ikegami

Respuesta

16

Antes de continuar, es importante comprender cómo funciona fork. Cuando fork un proceso, el sistema operativo usa la semántica copy-on-write para compartir la mayor parte de la memoria de los procesos primario y secundario; solo la cantidad de memoria que difiere entre el padre y el hijo debe asignarse por separado.

Para leer una sola línea de un archivo en Perl, aquí está una manera simple:

open my $fh, '<', $filePath or die "$filePath: $!"; 
my $line; 
while(<$fh>) { 
    if($. == $lineWanted) { 
     $line = $_; 
     last; 
    } 
} 

Esto utiliza la variable especial $. que contiene el número de línea del gestor de archivo actual.

4

Eche un vistazo a Tie::File módulo de núcleo.

+0

Pensé 'Tie :: File' era ineficaz en la memoria. ¿El OP no solicitó bajo uso de memoria? – Zaid

+0

@Zaid es razonablemente eficiente con la memoria; no almacena todo el contenido del archivo en la memoria, solo una lista de * offsets * de cada línea. No es gratis (incluso los escalares para mantener cada espacio de compensación tomar un poco de espacio por línea), pero por lo general es lo suficientemente bueno para manejar archivos de cientos de megabytes con facilidad. – hobbs

+0

@hobbs: Sí. Miré la documentación desde entonces (el comentario es bastante antiguo ahora) y deja bastante claro que no es un problema de memoria. – Zaid

0

No necesita tenedor. Como se puede imaginar, leer una línea específica de un archivo es una operación bastante común que ya hace uno de los 20k módulos en CPAN.

File::ReadBackwards es eficiente en cuanto a la memoria y rápido.

Cuestiones relacionadas