web-dev-qa-db-fra.com

Quelle est la meilleure façon de slurper un fichier dans une chaîne de Perl?

Oui, Il y a plus d'une façon de le faire Mais il doit y avoir une manière canonique ou la plus efficace ou la plus concise. Je vais ajouter des réponses que je connais et vois ce qui percolate au sommet.

Pour être clair, la question est la meilleure de lire le contenu d'un fichier dans une chaîne. Une solution par réponse.

47
dreeves

Que dis-tu de ça:

use File::Slurp;
my $text = read_file($filename);

ETA: Remarque Bug # 83126 pour File-Slurp: trou de sécurité avec codage (UTF-8) . Je recommande maintenant d'utiliser Fichier :: Slurper (Disclaimer: Je l'ai écrit), aussi parce qu'il a de meilleures valeur par défaut autour des codages:

use File::Slurper 'read_text';
my $text = read_text($filename);

ou chemin :: minuscule :

use Path::Tiny;
path($filename)->Slurp_utf8;
70
Leon Timmermans

J'aime faire cela avec un bloc do block dans lequel je localise @ARGV Donc, je peux utiliser l'opérateur de diamants pour faire le fichier magique pour moi.

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

Si vous avez besoin que cela soit un peu plus robuste, vous pouvez facilement le transformer en sous-programme.

Si vous avez besoin de quelque chose de vraiment robuste qui gère toutes sortes de cas spéciaux, utilisez fichier :: slurp . Même si vous n'allez pas l'utiliser, jetez un coup d'œil à la source pour voir toutes les situations loufoques qu'il doit gérer.fichier :: slurp a un gros problème de sécurité qui ne cherche pas à avoir une solution. Une partie de ceci est son défaillance de gérer correctement les codages. Même ma réponse rapide a ce problème. Si vous avez besoin de gérer le codage (peut-être parce que vous ne faites pas tout ce que UTF-8 par défaut), cela se développe à:

my $contents = do {
    open my $fh, '<:encoding(UTF-8)', $file or die '...';
    local $/;
    <$fh>;
    };

Si vous n'avez pas besoin de modifier le fichier, vous pourrez peut-être utiliser Fichier :: map .

44
brian d foy

En écrivant fichier :: slurp (qui est le meilleur moyen), Uri Guttman a fait beaucoup de recherches sur les nombreuses façons de la réduction et qui est la plus efficace. Il a écrit ses conclusions ici et les a incorporées Fichier d'information :: Slurp.

35
Schwern
open(my $f, '<', $filename) or die "OPENING $filename: $!\n";
$string = do { local($/); <$f> };
close($f);
20
dreeves

Choses à penser (surtout par rapport aux autres solutions):

  1. Filets lexicaux
  2. Réduire la portée
  3. Réduire la magie

Donc, je reçois:

my $contents = do {
  local $/;
  open my $fh, $filename or die "Can't open $filename: $!";
  <$fh>
};

Je ne suis pas un grand fan de magie <> sauf en utilisant la magie <>. Au lieu de le simuler, pourquoi ne pas simplement utiliser l'appel ouvert directement? Ce n'est pas beaucoup plus de travail et est explicite. (Vraie magie <>, surtout lors de la manipulation "-", est beaucoup plus de travail pour imiter parfaitement, mais nous ne l'utilisons pas ici de toute façon.)

11
Tanktalus

mMAP (mappage de mémoire) des chaînes peut être utile lorsque vous:

  • Avoir de très grandes chaînes, que vous ne voulez pas charger en mémoire
  • Vous voulez une initialisation rapide aveugle (vous obtenez des E/S progressivement sur l'accès)
  • Avoir un accès aléatoire ou paresseux à la chaîne.
  • Peut vouloir mettre à jour la chaîne, mais ne le prolongeant que les caractères:
#!/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);

Mise à jour: Mai 2012

Les éléments suivants doivent être assez bien équivalents après avoir remplacé SYS :: MMAP avec Fichier :: 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);
10
dwarring
use Path::Class;
file('/some/path')->Slurp;
8
me me
{
  open F, $filename or die "Can't read $filename: $!";
  local $/;  # enable Slurp mode, locally.
  $file = <F>;
  close F;
}
7
zigdon
use IO::All;

# read into a string (scalar context)
$contents = io($filename)->Slurp;

# read all lines an array (array context)
@lines = io($filename)->Slurp;
5
Prakash K

Voir le résumé de Perl6 :: slurp qui est incroyablement flexible et fait généralement la bonne chose avec très peu d'effort.

4
mopoke

Pour des doublures, vous pouvez généralement utiliser le -0 commutateur (avec -n) Pour rendre Perl lire l'ensemble du fichier à la fois (si le fichier ne contient pas d'octets nuls):

Perl -n0e 'print "content is in $_\n"' filename

Si c'est un fichier binaire, vous pouvez utiliser -0777:

Perl -n0777e 'print length' filename
3
Qtax

Voici une belle comparaison des moyens les plus populaires de le faire:

http://poundComment.wordpress.com/2009/08/02/perl-read-entiper-file/

3
dreeves

Candidat pour la pire façon de le faire! (Voir commentaire.)

open(F, $filename) or die "OPENING $filename: $!\n";
@lines = <F>;
close(F);
$string = join('', @lines);
1
dreeves

Ajustez la variable de séparateur de record spécial $/

undef $/;
open FH, '<', $filename or die "$!\n";
my $contents = <FH>;
close FH;
0
user4951120