2008-11-25 28 views
43

Tenga en cuenta que no estoy buscando la forma "correcta" de abrir/leer un archivo, o la forma en que debería abrir/leer un archivo cada vez. Me interesa saber qué usan la mayoría de las personas y, quizás, aprender algunos métodos nuevos al mismo tiempo:) *¿Cuál es la mejor manera de abrir y leer un archivo en Perl?

Un bloque de código muy común en mis programas Perl es abrir un archivo y leer o escribir en eso. He visto muchas maneras de hacerlo, y mi estilo al realizar esta tarea ha cambiado varias veces a lo largo de los años. Me pregunto cuál es el mejor método (si hay una mejor manera) para hacer esto?

que utiliza para abrir un archivo de la siguiente manera:

my $input_file = "/path/to/my/file"; 
open INPUT_FILE, "<$input_file" || die "Can't open $input_file: $!\n"; 

Pero creo que tiene problemas con la interceptación de errores.

Añadiendo un paréntesis parece fijar la interceptación de errores:

open (INPUT_FILE, "<$input_file") || die "Can't open $input_file: $!\n"; 

Sé que también puede asignar un gestor de archivo a una variable, por lo que en lugar de utilizar "archivo_entrada" como lo hice anteriormente, podría haber usado $ input_filehandle - ¿es así mejor?

Para leer un archivo, si es pequeño, ¿hay algún problema con el engomado, así?

my @array = <INPUT_FILE>; 

o

my $file_contents = join("\n", <INPUT_FILE>); 

o debería siempre bucle a través de, por ejemplo:

my @array; 
while (<INPUT_FILE>) { 
    push(@array, $_); 
} 

Sé que hay muchas maneras de lograr cosas en Perl, me pregunto si hay métodos preferidos/estándar para abrir y leer en un archivo?

+0

La página del manual [perlopentut] (http://perldoc.perl.org/perlopentut.html) cubre la mayor parte de este problema bastante bien. – converter42

Respuesta

58

No existen estándares universales, pero hay razones para preferir uno u otro. Mi forma preferida es la siguiente:

open(my $input_fh, "<", $input_file) || die "Can't open $input_file: $!"; 

Las razones son:

  • Usted reportar errores inmediatamente. (Reemplace "morir" por "advertir" si eso es lo que desea).
  • Su manejador de archivos ahora es de referencia, por lo que una vez que no lo esté utilizando, se cerrará automáticamente. Si usa el nombre global INPUT_FILEHANDLE, debe cerrar el archivo manualmente o permanecerá abierto hasta que el programa finalice.
  • El indicador de modo de lectura "<" está separado del $ input_file, lo que aumenta la legibilidad.

El siguiente es grande si el archivo es pequeño y usted sabe que quiere todas las líneas:

my @lines = <$input_fh>; 

Usted puede incluso hacer esto, si usted necesita para procesar todas las líneas como una sola cadena:

my $text = join('', <$input_fh>); 

Para archivos largos, querrá iterar sobre líneas con el tiempo, o use leer.

+0

o ligera variación ... abra mi $ input_fh, '<', $ input_file or die "No se puede abrir $ input_file: $!"; – draegtun

+2

Todavía pienso que esto es un texto repetitivo. Simplemente use 'File :: Slurp' o' Tie :: File'. – Svante

+0

__Nice edit tof! – monksy

14

Si desea que el archivo completo sea una sola cadena, no hay necesidad de recorrerlo.

use strict; 
use warnings; 
use Carp; 
use English qw(-no_match_vars); 
my $data = q{}; 
{ 
    local $RS = undef; # This makes it just read the whole thing, 
    my $fh; 
    croak "Can't open $input_file: $!\n" if not open $fh, '<', $input_file; 
    $data = <$fh>; 
    croak 'Some Error During Close :/ ' if not close $fh; 
} 

Los satisface anteriores perlcritic --brutal, lo cual es una buena manera de probar 'mejores prácticas' :). $input_file todavía no está definido aquí, pero el resto es kosher.

+0

¿Qué significa $ RS local = undef; ¿hacer? –

+2

'$ RS' es lo mismo que' $/'que' English' configura para usted. '$ /' Es la variable que rastrea el valor '' seperator' fila para <$fh> ', que es sinónimo de la noción de '' getline, o '$ FH> getline()'. En esencia, contiene el valor del algoritmo de lectura interno utiliza para saber cuando se ha leído un completo 'line' de los datos, y este valor está a' significa undef' "no hay un marcador que indica una línea completa" para que se lea en el conjunto archivo como una "línea" –

2

Si estos programas son solo para su productividad, ¡todo funciona! Incorpore todo el manejo de errores que crea que necesita.

Leer en un archivo completo si es grande puede no ser la mejor manera a largo plazo para hacer las cosas, por lo que es posible que desee procesar las líneas tal como vienen en lugar de cargarlas en una matriz.

Un consejo que obtuve de uno de los capítulos de El programador pragmático (Hunt & Thomas) es que tal vez le interese tener el script para guardar una copia de seguridad del archivo antes de que funcione para cortar y cortar en cubitos.

11

Si sus archivos son lo suficientemente pequeños como para poder leer todo en la memoria, utilice File::Slurp. Lee y escribe archivos completos con una API muy simple, además de realizar todas las comprobaciones de errores para que no sea necesario.

+1

File :: Slurp es impresionante, pero es mucho más lento que la lectura directa de Kent Fredric. (~ 4000 archivos 10-30k en 7s directos vs 56s sorbió por nytprof) –

6

No hay mejor manera de abrir y leer un archivo. Es la pregunta incorrecta para preguntar. ¿Qué hay en el archivo? ¿Cuántos datos necesitas en cualquier punto? ¿Necesitas todos los datos a la vez? ¿Qué necesitas hacer con los datos? Debe averiguarlos antes de pensar en cómo debe abrir y leer el archivo.

¿Algo que está haciendo ahora le causa problemas? Si no, ¿no tienes mejores problemas para resolver? :)

mayor parte de su pregunta no es más que la sintaxis, y eso es todo contestadas en la documentación de Perl (especialmente (perlopentut). También te para recoger Learning Perl, que responde a la mayoría de los problemas que tiene en su pregunta.

Buena suerte, :)

+0

Así que tal vez no debería haber preguntado cuál es la mejor manera de abrir/leer un archivo es, pero lo que hacen la mayoría de la gente. He escrito cientos de programas perl que abren archivos, y solo quiero asegurarme de que lo estoy haciendo bien. No he tenido ningún problema, solo tengo curiosidad de cómo lo hacen otras personas. ¡Gracias! – BrianH

+0

De nuevo, lea el primer párrafo. La mejor manera depende de lo que estás haciendo. –

+0

No digo que Perl :: Critic sea la ley, pero muchas de las formas de abrir archivos en "Learning Perl" no pasan Perl :: Critic. De hecho, la forma en que solía abrir archivos todo el tiempo es la forma en que lo aprendí en "Learning Perl". Yo diría que las mejores prácticas se pueden aplicar a la mayoría de las situaciones en las que se necesita abrir un archivo, y que no es necesario que conozca los pequeños detalles; de lo contrario, preguntaría: "¿Cuál es la mejor manera de abrir un archivo binario y contar? los bytes "o algo así. El 99% de los archivos que abro son texto plano, y solo quiero leerlo en una matriz. Estoy interesado en conocer las mejores prácticas – BrianH

5

para OO, me gusta:

use FileHandle; 
... 
my $handle = FileHandle->new("< $file_to_read"); 
croak("Could not open '$file_to_read'") unless $handle; 
... 
my $line1 = <$handle>; 
my $line2 = $handle->getline; 
my @lines = $handle->getlines; 
$handle->close; 
+0

¿Y luego lo lee con <$handle>? – BrianH

+0

sí, va a trabajar con el "operador de iteración", pero también se puede leer con manija de $> $ getline o manejar-> getlines – Axeman

5

es cierto que hay tantas mejores formas de abrir un archivo en Perl, ya que hay

$files_in_the_known_universe * $perl_programmers 

... pero sigue siendo interesante ver quién lo hace normalmente. Mi forma preferida de sorber (leer todo el archivo a la vez) es:

use strict; 
use warnings; 

use IO::File; 

my $file = shift @ARGV or die "what file?"; 

my $fh = IO::File->new($file, '<') or die "$file: $!"; 
my $data = do { local $/; <$fh> }; 
$fh->close(); 

# If you didn't just run out of memory, you have: 
printf "%d characters (possibly bytes)\n", length($data); 

Y al ir línea por línea:

my $fh = IO::File->new($file, '<') or die "$file: $!"; 
while (my $line = <$fh>) { 
    print "Better than cat: $line"; 
} 
$fh->close(); 

Advertencia lector, por supuesto: estos son sólo los enfoques I' Estoy comprometido con la memoria muscular para el trabajo diario, y pueden ser radicalmente inadecuados para el problema que está tratando de resolver.

4

una vez que utilizó el texto modelo

open (FILEIN, "<", $inputfile) or die "..."; 
my @FileContents = <FILEIN>; 
close FILEIN; 

regularidad.Hoy en día, utilizo File::Slurp para archivos pequeños que quiero mantener completamente en la memoria, y Tie::File para archivos grandes que quiero abordar de manera escamosa y/o archivos que deseo cambiar en su lugar.

12

Tener que escribir 'o morir' en todas partes me vuelve loco. Mi forma preferida para abrir un archivo tiene el siguiente aspecto:

use autodie; 

open(my $image_fh, '<', $filename); 

Mientras que eso es muy poco escribir, hay un montón de cosas importantes a tener en cuenta que están pasando:

  • Estamos utilizando el autodie pragma, lo que significa que todos los integradores de Perl lanzarán una excepción si algo sale mal. Elimina la necesidad de escribir or die ... en su código, produce mensajes de error amigables y legibles por el ser humano, y tiene alcance léxico. Está disponible desde el CPAN.

  • Estamos usando la versión de tres argumentos de open. Esto significa que incluso si tenemos un nombre de archivo gracioso que contiene caracteres como <, > o |, Perl seguirá haciendo lo correcto. En mi Perl Security tutorial en OSCON mostré una serie de maneras de obtener 2 argumentos open para portarse mal. Las notas para este tutorial están disponibles para free download from Perl Training Australia.

  • Estamos usando un controlador de archivo escalar. Esto significa que no vamos a cerrar de manera coincidente el identificador de archivo de otra persona con el mismo nombre, lo que puede suceder si usamos identificadores de archivo de paquete. También significa que strict puede detectar errores tipográficos, y que nuestro identificador de archivo se limpiará automáticamente si se sale del alcance.

  • Estamos utilizando un identificador de archivo significativo. En este caso, parece que vamos a escribir en una imagen.

  • El controlador del archivo finaliza con _fh. Si vemos que lo usamos como un escalar normal, entonces sabemos que probablemente sea un error.

+0

gran visión, gracias! Además, nunca había visto el método de 3 argumentos para "abrir". ¡Creo que me gusta así! Gracias! – BrianH

3

leer todo el archivo $ archivo en $ texto variable con una sola línea

$text = do {local(@ARGV, $/) = $file ; <>}; 

o como una función

$text = load_file($file); 
sub load_file {local(@ARGV, $/) = @_; <>} 
1

Damian Conway hace de esta manera:

$data = readline!open(!((*{!$_},$/)=\$_)) for "filename"; 

Pero no se lo recomiendo.

+0

¿Cómo funciona? –

+0

establece $/a undef (modo sorber) y asigna \ $ _ a * {""}; la asignación de una referencia a un globo solo reemplaza la ranura del tipo de referencia, por lo que $ {""} es un alias de $ _ (que tiene el valor "nombre de archivo"). el ! niega el valor de la tarea (1 dado que una asignación de lista en contexto escalar da la cantidad de elementos a la derecha de la tarea), por lo que es falso. open trata el valor falso como "", por lo que abre el identificador de archivo * {""}, y un arg abierto obtiene el nombre de archivo para abrir desde el escalar del glob. si open devuelve true, la línea de lectura también trata lo falso dado por! como el * {""} archivador – ysth

2

El operador || tiene mayor prioridad, por lo que se evalúa primero antes de enviar el resultado para "abrir" ... En el código que ha mencionado, use el operador "o" en su lugar, y no tendría esa problema.

open INPUT_FILE, "<$input_file" 
    or die "Can't open $input_file: $!\n"; 
Cuestiones relacionadas