2010-05-11 23 views
13

¿Cómo lee Perl en los archivos, cómo le indica que avance a la siguiente línea en el archivo de texto y cómo lo hace leer todas las líneas en el archivo .txt hasta, por ejemplo, alcanza el elemento "plátano"?Lectura SIMPLE de archivos en Perl

Respuesta

18

Básicamente, existen dos formas de lectura de archivos:

  1. Slurping un archivo significa leer el archivo a la vez. Esto usa mucha memoria y demora un poco, pero luego todo el contenido del archivo está en la memoria y puede hacer lo que quiera con él.
  2. Leer un archivo de línea por línea (en un ciclo while) es mejor si no desea leer todo el archivo (por ejemplo, detenerse cuando llegue a "banana").

Para ambas formas que necesita para crear un FILEHANDLE utilizando el comando "open", así:

open(my $yourhandle, '<', 'path/to/file.txt') # always use a variable here containing filename 
    or die "Unable to open file, $!"; 

entonces usted puede sorber el archivo poniéndolo en una matriz:

my @entire_file=<$yourhandle>; # Slurp! 

o leer el archivo uno por uno usando un bucle while

while (<$yourhandle>) { # Read the file line per line (or otherwise, it's configurable). 
    print "The line is now in the $_ variable"; 
    last if $_ eq 'banana'; # Leave the while-loop. 
} 

Después, no olvide cerrar el archivo.

close($yourhandle) 
    or warn "Unable to close the file handle: $!"; 

Eso es sólo lo básico .. hay mucho que ver con los archivos, especialmente en Tratamiento de excepciones (lo que hay que hacer cuando no existe el archivo, no es legible, se está escribiendo a), por lo que tiene que leer o pedir a distancia :)

+0

¡Impresionante! Justo lo que estaba buscando, ¡gracias! – Befall

+1

No use esto para el código de producción, esto es solo para comenzar a aprender. ¡Asegúrate de buscar excepciones en todos lados! – Konerak

+3

Konerak, ¿podría comenzar a utilizar y enseñar los manejadores de archivos léxicos? – daxim

1

en primer lugar, usted tiene que abrir el archivo:

open (my $SOME_FILEHANDLE, "<", "filename.txt"); 

Es posible que desee comprobar si la apertura del expediente se ha realizado correctamente:

open (my $SOME_FILEHANDLE, "<", "filename.txt") or die "could not open filename"; 

Después de abrir el archivo, puede leer la línea por línea desde $ SOME_FILEHANDLE. Se obtiene la siguiente línea con el constructo <$SOME_FILEHANDLE>:

my $next_line = <$SOME_FILEHANDLE>; 

$next_line es indefinido tras la lectura de la última línea. Por lo tanto, se puede poner toda la cosa en un bucle while:

while (my $next_line = <$SOME_FILEHANDLE>) { 
    do_something($next_line); 
} 

Esto funciona porque un valor indefinido evalúa a false en la condición de tiempo.

Si desea salir del bucle cuando se encuentra "banana", es probable que utilice una expresión regular para comprobar si el plátano:

while (my $next_line = <$SOME_FILEHANDLE>) { 
    last if $next_line =~ /banana/; 
    do_something($next_line); 
} 

El operador last sale del bucle while y se "dispara" cuando $next_line coincide con banana.

+0

Más información útil, increíble, ¡gracias! – Befall

+2

René, ¿podría comenzar a usar y enseñar los manejadores de archivos léxicos? – daxim

+1

Luego tome este voto a favor como desaliento de las prácticas obsoletas. – daxim

17

René y Konerak escribieron un par de respuestas bastante buenas que muestran cómo abrir y leer un archivo. Lamentablemente, tienen algunos problemas en términos de promoción de mejores prácticas.Por lo tanto, llegaré tarde a la fiesta y trataré de agregar una explicación clara del enfoque de mejores prácticas y por qué es mejor utilizar el enfoque de mejores prácticas.

¿Qué es un archivo handle?

A identificador de archivo es un nombre que utilizamos que representa el archivo en sí. Cuando desee operar en un archivo (léalo, escríbalo, muévase, etc.) use el identificador de archivo para indicar en qué archivo operar. Un identificador de archivo es distinto del nombre o ruta del archivo.

Ámbito de la variable y el archivo se encarga de

El ámbito de una variable determina en qué partes de un programa de la variable puede ser visto. En general, es una buena idea mantener el alcance de cada variable lo más pequeño posible para que las diferentes partes de un programa complejo no se rompan entre sí.

La forma más fácil de controlar estrictamente el alcance de una variable en Perl es convertirla en una variable léxica . Las variables léxicas solo son visibles dentro del bloque en el que están declaradas. Utilice my para declarar una variable léxica: my $foo;

# Can't see $foo here 

{ my $foo = 7; 
    print $foo; 
} 

# Can't see $foo here 

identificadores de archivo Perl pueden ser globales o léxico. Cuando usa abrir con una palabra simple (una cadena literal sin comillas o un sigilo), crea un identificador global. Cuando abre en un escalar léxico indefinido, crea un manipulador léxico.

open FOO, $file;  # Global file handle 
open my $foo, $file; # Lexical file handle 

# Another way to get a lexical handle: 
my $foo; 
open $foo, $file; 

El gran problema con los identificadores de archivos globales es que son visibles en cualquier parte del programa. Entonces, si creo un manejador de archivo llamado FOO en subrutina, debo ser muy cuidadoso para asegurarme de que no utilizo el mismo nombre en otra rutina, o si uso el mismo nombre, debo estar absolutamente seguro de que bajo ninguna circunstancia puedo ellos entran en conflicto el uno con el otro. La alternativa más simple es usar un manejador léxico que no puede tener el mismo tipo de conflictos de nombre.

Otro beneficio de los manejadores léxicos es que es fácil pasarlos como argumentos de subrutina.

La función open

La función open tiene todo tipo de características. Puede ejecutar subprocesos, leer archivos e incluso proporcionar un control para el contenido de un escalar. Puede alimentarlo con muchos tipos diferentes de listas de argumentos. Es muy potente y flexible, pero estas características vienen con algunas trampas (la ejecución de subprocesos no es algo que quieras hacer por accidente).

Para el caso simple de abrir un archivo, lo mejor es utilizar siempre la forma 3-argumento, ya que evita la activación involuntaria de todas esas características especiales:

open FILEHANDLE, MODE, FILEPATH 

FILEHANDLE es el identificador de archivo para abrir.

MODE es cómo abrir el archivo, > de sobreescritura, '>>for write in append mode, +>for read and write, and < `para lectura.

FILEPATH es la ruta al archivo para abrir.

En caso de éxito, open devuelve un valor verdadero. En caso de error, $! se configura para indicar el error y se devuelve un valor falso.

tanto, para que un identificador de archivo de léxico con un 3-argumento open que podemos utilizar para leer un archivo:

open my $fh, '<', $file_path; 

Los valores de retorno lógicas que sea fácil de comprobar si hay errores:

open my $fh, '<', $file_path 
    or die "Error opening $file_path - $!\n"; 

Me gusta reducir el tratamiento de errores a una nueva línea y aplicar sangría, pero ese es el estilo personal.

cierre maneja

Cuando usa manijas globales es crítico con cuidado, cierre explícitamente todas y cada mango cuando haya terminado con él. De lo contrario, pueden surgir errores extraños y problemas de mantenimiento.

close FOO; 

léxico maneja cerrará automáticamente cuando se destruye la variable (cuando el recuento de referencias llega a 0, por lo general cuando la variable se sale del ámbito).

Cuando se utilizan manejadores léxicos, es común confiar en el cierre implícito de identificadores en lugar de cerrarlos explícitamente.

Diamantes son el mejor amigo de Perl.

El operador de diamante, <>, nos permite iterar sobre un identificador de archivo. Al igual que open tiene superpoderes. Ignoraremos a la mayoría de ellos por ahora. (Sin embargo, busque información en el separador de registros de entrada, el separador de registros de salida y el manejador de archivos NULL).

Lo importante es que en el contexto escalar (por ejemplo, asignar a un escalar) actúa como readline función. En el contexto de la lista (por ejemplo, asignar a una matriz) actúa como una función read_all_lines.

Imagínese que usted quiere leer un archivo de datos con tres líneas de cabecera (fecha, hora y ubicación) y un montón de líneas de datos:

open my $fh, '<', $file_path 
    or die "Ugh - $!\n"; 

my $date = <$fh>; 
my $time = <$fh>; 
my $loc = <$fh>; 

my @data = <$fh>; 

Está en común escuchar a la gente habla de sorber un archivo. Esto significa leer todo el archivo en una variable a la vez.

# Slurp into array 
my @slurp = <$fh>; 

# Slurp into a scalar - uses tricks outside the scope of this answer 
my $slurp; 
{ local $/ = undef; $slurp = <$fh>; } 

Poniendo todo junto

open my $fh, '<', 'my_file' 
    or die "Error opening file - $!\n"; 

my @before_banana; 

while(my $line = <$fh>) { 
    last if $line =~ /^banana$/; 

    push @before_banana, $line; 
} 

Poniendo todo junto - edición especial de crédito adicional

my $fh = get_handle('my_file'); 

my @banana = read_until($fh, qr/^banana$/); # Get the lines before banana 

read_until($fh, qr/^no banana$/);   # Skip some lines 

my @potato = read_until($fh, qr/^potato$/); # Get the lines before potato 

sub get_handle { 
    my $file_path = shift; 

    open my $fh, '<', $file_path 
     or die "Can't open '$file_path' for reading - $!\n"; 

    return $fh; 
} 

sub read_until { 
    my $fh = shift; 
    my $match = shift; 

    my @lines; 

    while(my $line = <$fh>) { 
     last if $line =~ /$match/; 
     push @line, $line; 
    } 

    return @lines; 
} 

¿Por qué tantas maneras diferentes? ¿Por qué tantos errores?

Perl es un lenguaje antiguo; tiene un bagaje que data de 1987. A lo largo de los años se encontraron varios problemas de diseño y se hicieron arreglos, pero solo en raras ocasiones se permitieron soluciones para perjudicar la compatibilidad con versiones anteriores.

Además, Perl está diseñado para darle la flexibilidad de hacer lo que quiera, cuando lo desee. Es muy permisivo Lo bueno de esto es que puedes alcanzar las oscuras profundidades y hacer cosas mágicas realmente geniales. Lo malo es que es fácil dispararse en el pie si olvida templar su exuberancia y no centrarse en producir código legible.

El hecho de que tenga cuerda más que suficiente, no significa que deba ahorcarse.

+1

WOW, esto es increíble. Gracias por una respuesta tan profunda, realmente lo aprecio. Esto me ayuda a entender el proceso una tonelada. – Befall

+1

@daotoad: ¡¡¡Gran respuesta !! –

+0

¿No se cierran los identificadores globales cuando finaliza el proceso (si no es así, efectivamente por el sistema operativo)? ¿O pueden los datos realmente perderse para un identificador de archivo global que se utiliza para escribir y no se cierra en el script de Perl? –