122 votes

En Perl, comment puis-je lire un fichier entier dans une chaîne de caractères ?

J'essaie d'ouvrir un fichier .html sous la forme d'une longue chaîne de caractères. Voici ce que j'ai obtenu :

open(FILE, 'index.html') or die "Can't read file 'filename' [$!]\n";  
$document = <FILE>; 
close (FILE);  
print $document;

ce qui entraîne :

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN

Cependant, je veux que le résultat ressemble à ceci :

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

De cette façon, je peux rechercher plus facilement dans l'ensemble du document.

8 votes

Vous devriez vraiment vérifier quelle est la définition de "Cant install", c'est un problème courant et c'est souvent un argument qui n'a pas besoin d'être avancé. stackoverflow.com/questions/755168/perl-myths/

1 votes

Je suis en fait incapable de modifier quoi que ce soit sur l'ensemble du serveur sur lequel ce script est exécuté, à part le script lui-même.

0 votes

Donc vous n'êtes pas autorisé à ajouter des fichiers, n'importe où sur le serveur ?

99voto

Chas. Owens Points 40887

Je le ferais comme ça :

my $file = "index.html";
my $document = do {
    local $/ = undef;
    open my $fh, "<", $file
        or die "could not open $file: $!";
    <$fh>;
};

Notez l'utilisation de la version à trois arguments de open. Elle est beaucoup plus sûre que les anciennes versions à deux (ou un) arguments. Notez également l'utilisation d'un gestionnaire de fichier lexical. Les gestionnaires de fichiers lexicaux sont plus agréables que les anciennes variantes à mots nus, pour de nombreuses raisons. Nous profitons ici de l'une d'entre elles : elles se ferment lorsqu'elles sortent de leur portée.

9 votes

Il s'agit probablement de la meilleure façon de le faire, car elle utilise à la fois l'ouverture à 3 arguments et le maintien de la variable INPUT_RECORD_SEPARATOR ($/) localisée dans le plus petit contexte requis.

85voto

Sinan Ünür Points 76179

Ajouter :

 local $/;

avant de lire le fichier. Voir Comment puis-je lire un fichier entier en une seule fois ? ou

$ perldoc -q "entire file"

Voir Variables relatives aux manipulations de fichiers en perldoc perlvar y perldoc -f local .

Au passage, si vous pouvez mettre votre script sur le serveur, vous pouvez avoir tous les modules que vous voulez. Voir Comment puis-je conserver mon propre répertoire de modules/bibliothèques ? .

En outre, Chemin::Classe::Fichier vous permet de slurp y cracher .

Path::Tiny donne encore plus de méthodes pratiques telles que slurp , slurp_raw , slurp_utf8 ainsi que leurs spew contreparties.

35 votes

Vous devriez probablement expliquer les effets de la localisation de $/ ainsi que son objectif.

12 votes

Si vous n'allez pas expliquer quoi que ce soit sur la localisation $/ vous devriez probablement ajouter des liens pour de plus amples informations.

7 votes

Une bonne explication étape par étape de ce qui se fait : { local $/ ; <$fh> } est fournie ici : perlmonks.org/?node_id=287647

79voto

Quentin Points 325526

Con Fichier::Slurp :

use File::Slurp;
my $text = read_file('index.html');

Oui, même vous pouvez utiliser CPAN .

0 votes

L'OP a dit qu'il ne peut rien modifier sur le serveur. Le lien "Oui, même vous pouvez utiliser CPAN" ici vous montre comment contourner cette limitation, dans la plupart des cas.

0 votes

Can't locate File/Slurp.pm in @INC (@INC contains: /usr/lib/perl5/5.8/msys :(

2 votes

@Dmitry - Installez donc le module. Il y a un lien vers les instructions d'installation sur la page metacpan à laquelle j'ai fait référence dans cette réponse.

56voto

jrockway Points 23734

Tous les messages sont légèrement non-idiomatiques. L'idiome est :

open my $fh, '<', $filename or die "error opening $filename: $!";
my $data = do { local $/; <$fh> };

La plupart du temps, il n'est pas nécessaire de mettre $/ pour undef .

3 votes

local $foo = undef est juste la méthode suggérée par Perl Best Practice (PBP). Si nous publions des extraits de code, je pense que faire de notre mieux pour que ce soit clair serait une bonne chose.

2 votes

Montrer aux gens comment écrire du code non-idiomatique est une bonne chose ? Si je voyais "local $/ = undef" dans du code sur lequel je travaille, ma première action serait d'humilier publiquement l'auteur sur irc. (Et je ne suis généralement pas pointilleux sur les questions de "style").

1 votes

Ok, je vais mordre : qu'est-ce qui est exactement digne de moquerie dans "local $/ = undef" ? Si votre seule réponse est "C'est non-idiomatique", alors (a) je n'en suis pas si sûr et (b) et alors ? Je n'en suis pas si sûr, parce que c'est un moyen terriblement courant de faire cela. Et alors, parce que c'est parfaitement clair et raisonnablement bref. Vous êtes peut-être plus pointilleux que vous ne le pensez sur les questions de style.

19voto

brian d foy Points 71781

De perlfaq5 : Comment puis-je lire un fichier entier en une seule fois ? :


Vous pouvez utiliser le module File::Slurp pour le faire en une seule étape.

use File::Slurp;

$all_of_it = read_file($filename); # entire file in scalar
@all_lines = read_file($filename); # one line per element

L'approche habituelle de Perl pour traiter toutes les lignes d'un fichier est de le faire une ligne à la fois :

open (INPUT, $file)     || die "can't open $file: $!";
while (<INPUT>) {
    chomp;
    # do something with $_
    }
close(INPUT)            || die "can't close $file: $!";

C'est beaucoup plus efficace que de lire l'ensemble du fichier en mémoire sous forme de tableau de lignes et de le traiter un élément à la fois, ce qui est souvent, voire presque toujours, la mauvaise approche. Chaque fois que vous voyez quelqu'un faire cela :

@lines = <INPUT>;

vous devriez réfléchir longuement et sérieusement à la raison pour laquelle vous avez besoin de tout charger en même temps. Ce n'est tout simplement pas une solution évolutive. Vous pourriez également trouver plus amusant d'utiliser le module standard Tie::File, ou les liaisons $DB_RECNO du module DB_File, qui vous permettent de lier un tableau à un fichier de sorte que l'accès à un élément du tableau donne accès à la ligne correspondante dans le fichier.

Vous pouvez lire le contenu entier du fichier dans un scalaire.

{
local(*INPUT, $/);
open (INPUT, $file)     || die "can't open $file: $!";
$var = <INPUT>;
}

Cela défait temporairement votre séparateur d'enregistrement, et ferme automatiquement le fichier à la sortie du bloc. Si le fichier est déjà ouvert, utilisez simplement ceci :

$var = do { local $/; <INPUT> };

Pour les fichiers ordinaires, vous pouvez également utiliser la fonction de lecture.

read( INPUT, $var, -s INPUT );

Le troisième argument teste la taille en octets des données du fichier INPUT et lit ce nombre d'octets dans le tampon $var.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X