regular - ¿Cuál es la mejor manera de sorber un archivo en una cadena en Perl?
expresiones regulares perl online (17)
Ajuste la variable especial del separador de registros $/
undef $/;
open FH, ''<'', $filename or die "$!/n";
my $contents = <FH>;
close FH;
Sí, hay más de una forma de hacerlo, pero debe ser canónica, más eficiente o más concisa. Agregaré respuestas que conozco y veré qué se filtra a la cima.
Para ser claros, la pregunta es cómo mejor leer el contenido de un archivo en una cadena. Una solución por respuesta.
Al escribir File::Slurp (que es la mejor manera), Uri Guttman hizo una gran cantidad de investigaciones sobre las diversas formas de sorber y cuál es la más eficiente. Escribió sus hallazgos aquí y los incorporó a la información File :: Slurp.
Aquí hay una buena comparación de las formas más populares de hacerlo:
http://poundcomment.wordpress.com/2009/08/02/perl-read-entire-file/
Candidato a la peor manera de hacerlo! (Ver comentario.)
open(F, $filename) or die "OPENING $filename: $!/n";
@lines = <F>;
close(F);
$string = join('''', @lines);
Cosas en que pensar (especialmente cuando se compara con otras soluciones):
- Manejadores de archivos léxicos
- Reducir alcance
- Reducir la magia
Entonces entiendo:
my $contents = do {
local $/;
open my $fh, $filename or die "Can''t open $filename: $!";
<$fh>
};
No soy un gran admirador de la magia <> excepto cuando uso magia <>. En lugar de fingir, ¿por qué no usar la llamada abierta directamente? No es mucho más trabajo, y es explícito. (True magic <>, especialmente cuando se maneja "-", es mucho más trabajo emular a la perfección, pero de todos modos no lo estamos usando).
Esto no es ni rápido, ni independiente de la plataforma, y realmente malvado, pero es corto (y lo he visto en el código de Larry Wall ;-):
my $contents = `cat $file`;
Niños, no hagas eso en casa ;-).
Me gusta hacer esto con un bloque do
en el que @ARGV
para poder usar el operador de diamante para hacer la magia de archivo para mí.
my $contents = do { local(@ARGV, $/) = $file; <> };
Si necesita que esto sea un poco más robusto, puede convertirlo fácilmente en una subrutina.
Si necesita algo realmente robusto que maneje todo tipo de casos especiales, use File::Slurp . Incluso si no va a usarlo, eche un vistazo a la fuente para ver todas las situaciones extrañas que tiene que manejar. File::Slurp tiene un gran problema de seguridad que no parece tener una solución. Parte de esto es su falla al manejar adecuadamente las codificaciones. Incluso mi respuesta rápida tiene ese problema. Si necesita manejar la codificación (tal vez porque no hace todo UTF-8 por defecto), esto se expande a:
my $contents = do {
open my $fh, ''<:encoding(UTF-8)'', $file or die ''...'';
local $/;
<$fh>;
};
Si no necesita cambiar el archivo, es posible que pueda usar File::Map .
Nadie dijo nada sobre read o sysread, así que aquí hay una manera simple y rápida:
my $string;
{
open my $fh, ''<'', $file or die "Can''t open $file: $!";
read $fh, $string, -s $file; # or sysread
close $fh;
}
Para frases sencillas, generalmente puede usar el -0
(con -n
) para hacer que perl lea todo el archivo a la vez (si el archivo no contiene ningún nulo):
perl -n0e ''print "content is in $_/n"'' filename
Si es un archivo binario, puede usar -0777
:
perl -n0777e ''print length'' filename
Qué tal esto:
use File::Slurp;
my $text = read_file($filename);
ETA: nota el error # 83126 para File-Slurp: agujero de seguridad con codificación (UTF-8) . Ahora recomiendo usar File::Slurper (descargo de responsabilidad: lo escribí), también porque tiene mejores valores predeterminados en cuanto a las codificaciones:
use File::Slurper ''read_text'';
my $text = read_text($filename);
o Path::Tiny :
use Path::Tiny;
path($filename)->slurp_utf8;
Vea el resumen de Perl6::Slurp que es increíblemente flexible y generalmente hace lo correcto con muy poco esfuerzo.
mmap (asignación de memoria) de cadenas puede ser útil cuando:
- Tiene cadenas muy grandes, que no desea cargar en la memoria
- Quiere una inicialización ciegamente rápida (obtiene acceso de E / S gradual)
- Tener acceso aleatorio o perezoso a la cadena.
- Puede querer actualizar la cadena, pero solo la está extendiendo o reemplazando caracteres:
#!/usr/bin/perl
use warnings; use strict;
use IO::File;
use Sys::Mmap;
sub sip {
my $file_name = shift;
my $fh;
open ($fh, ''+<'', $file_name)
or die "Unable to open $file_name: $!";
my $str;
mmap($str, 0, PROT_READ|PROT_WRITE, MAP_SHARED, $fh)
or die "mmap failed: $!";
return $str;
}
my $str = sip(''/tmp/words'');
print substr($str, 100,20);
Actualización: mayo de 2012
Lo siguiente debería ser bastante equivalente, después de reemplazar Sys::Mmap con File::Map
#!/usr/bin/perl
use warnings; use strict;
use File::Map qw{map_file};
map_file(my $str => ''/tmp/words'', ''+<'');
print substr($str, 100, 20);
# Takes the name of a file and returns its entire contents as a string.
sub getfile
{
my($filename) = @_;
my($result);
open(F, $filename) or die "OPENING $filename: $!/n";
while(<F>) { $result .= $_; }
close(F);
return $result;
}
open(my $f, ''<'', $filename) or die "OPENING $filename: $!/n";
$string = do { local($/); <$f> };
close($f);
use IO::All;
# read into a string (scalar context)
$contents = io($filename)->slurp;
# read all lines an array (array context)
@lines = io($filename)->slurp;
use Path::Class;
file(''/some/path'')->slurp;
{
open F, $filename or die "Can''t read $filename: $!";
local $/; # enable slurp mode, locally.
$file = <F>;
close F;
}