Table des matières
Les fichiers
1. Descripteurs
Pour manipuler un fichier, il faut d'abord obtenir une “poignée” ou “descripteur” (handle) permettant de le saisir.
Syntaxes
Perl peut également manipuler ces descripteurs avec deux types de syntaxe. La syntaxe “ancienne” ou traditionnelle utilise des noms en majuscules avec uniquement des lettres, et ne sont jamais déclarés et assignés. La portée de ces descripteurs est globale :
open(TEXT, ">text"); print TEXT "Bonjour le monde.\n"; close(TEXT);
La deuxième syntaxe, plus “attendue” permet d'utiliser une variable standard et donc locale (il s'agit en fait d'une référence vers un descripteur) :
open(my $text, ">text"); print $text "Bonjour le monde.\n"; close($text);
Notons qu'il existe une version moderne (orienté objet) qui requiert l'utilisation d'un module spécifique (cf man filehandle) :
use FileHandle; $text = new FileHandle(">text"); print $text "Bonjour le monde.\n"; $text->close();
Descripteurs implicites
Perl utilise plusieurs descripteurs implicites par défaut, qui peuvent être nommés:
- STDOUT: l'entrée standard, qui est naturellement utilisée par print et consorts
- STDERR: la sortie d'erreur, utilisée notamment par die
- STDIN: l'entrée standard, utilisée par défaut par l'opérateur de lecture <>
2. Ouverture
Via le shell
La façon la plus économique d'ouvrir un fichier et de ne pas le faire, ou plus simplement de déléguer cette tâche au shell. Ainsi il suffit d'appeler l'interpréteur Perl en redirigeant les fichiers ou programmes de son choix sur l'entrée ou la sortie standard :
$ ./test.pl <input 2>error.log |grep qqchose
Mode simple
On utilise la fonction open, qui accepte comme nom de fichier une syntaxe ressemblant au shell et permettant de désigner les différents scenarios d'ouverture :
open(FILE, “test”) | Lecture seule |
---|---|
open(FILE, “<test”) | Lecture seule |
open(FILE, “>test”) | Ecriture avec troncature |
open(FILE, “»test”) | Ecriture en fin de fichier |
open(FILE, “+<test”) | Lecture/écriture (fichier existant, sans troncature) |
open(FILE, “+>test”) | Lecture/écriture (troncature, création de fichier si nécessaire) |
open(FILE, “+»test”) | Lecture/écriture (sans troncature, écriture depuis la fin, création de fichier si nécessaire) |
Avec une variable
Il est important de noter qu'avec l'utilisation de variables classiques Perl, un fichier est automatiquement fermé dès que l'on quitte la portée de la variable :
sub log_error { open(my $log, ">>error.log") or die; print $log @_; }
Avec des programmes
On peut facilement reproduire le mécanisme du “pipe” utilisé dans le shell, c'est-à-dire relier sur l'entrée ou la sortie standard un autre programme :
open(MAIL, "|sendmail -bi") or die; print MAIL "From: eleve@insia.org\r\nSubject: test\r\n"; close MAIL; open(LOG, "gzip mail.1.gz|") or die; while(<LOG>) { print $_ if /error/; } close FILES;
Ceci implique bien entendu que Perl se charge d'exécuter ces programmes à votre demande, c'est une forme altrenative d'invocation de commande (cf. system et l'opérateur backtick).
Note: pour la communication bi-directionnelle avec un programme, voir le module IPC::Open2.
Le fichier '-'
Il existe un fichier spécial nommé - (moins, minus) qui permet de désigner l'entrée standard ou la sortie standard du script, selon la direction utilisée. Il est notable que si on utilise le préfixe pipe, le programme exécuté est une autre instance du script (en d'autre termes, il s'agit d'un fork déguisé).
Appels systèmes directs
Les fonctions d'ouvertures (puis de lecture/écriture) de Perl reposent sur leur équivalent libc fopen, fread, …. On profite ainsi de mécanismes haut niveau: pas de gestion de buffers, d'écritures partielles, etc. Parfois cela peut être un obstacle, surtout si l'on cherche à communiquer avec des fichiers spéciaux (périphériques) ou en utilisant des protocoles binaires.
Dans ce cas on peut utiliser les appels systèmes POSIX standard :
use Fcntl; # Imports O_xxx constants sysopen(FILE, "/dev/ttyS0", O_RDWR) or die; while(sysread(FILE, $buf, 32)) { my $to_say = "You said: $buf\n"; my $to_send = length($to_say); my $sent = syswrite(FILE, $to_say, $to_send); print "transmit: $sent/$to_send\n"; } close FILE;
Mode binaire
Sur certains systèmes aux concepts curieux, le mode par défaut d'accès à un fichier n'est pas transparent (un octet pour un octet), mais interprété. Typiquement, un “\n” sera réellement écrit “\r\n” sous MS Windows. On doit alors utiliser explicitement un mode “binaire” pour ces systèmes (la fonction sera sans effet sur les systèmes conventionnels) :
binmode(FILE);
3. Lecture
Par blocs
On peut lire une quantité de donnée quelconque depuis un fichier simplement à l'aide de read :
read(FILE, $buffer, 1500); read(FILE, $buffer, 1500, 2000); # Lit à partir du 2000ème octet seek(FILE, 5000); # Positionne le curseur de lecture au 5000ème octet
Par enregistrement
Il s'agit de l'utilisation de loin la courante en Perl, elle est même intégrée en tant qu'opérateur : <>. Le séparateur d'enregistrement peut être modifiée à tout moment à l'aide de la variable spéciale $/ (qui désigne le retour chariot par défaut) :
$/ = "\n\n"; # Découpe en "paragraphes" while (<FILE>) { print "<p> $_ </p>\n"; }
L'opérateur renvoie le dernier enregistrement lu, ou undef si la fin du fichier est rencontré. Il est ainsi traditionnellement appelé dans le test d'une boucle while, l'enregistrement courant étant alors implicitement dans la variable $_.
Il est possible de lire un fichier entier en un seul appel en utilisant la chaîne vide comme séparateur :
$/ = ""; my $whole = <FILE>; # Lit tout le fichier dans $whole
Note: une technique alternative, empruntée au shell serait my $whole = `cat $filename`;.
4. Ecriture
Formatée
Il existe de nombreuses fonctions de formattage, dont les fameux print, printf, write et format :
print FILE "Une information...\n";
Note: write n'est pas le pendant de read ! (Il n'est pas nécessaire, il suffit de manipuler les chaînes et uiliser seek).
Sortie par défaut
Il est possible de changer momentanément le fichier de sortie par défaut, ce qui permet de rediriger facilement la sortie d'un sous-programme sans avoir à le modifier :
make_report(); # Sortie sur STDOUT my $previous = select(LOG); make_report(); # Sortie dans LOG select($previous);
Bufferisation
Par défaut, les appels haut niveau (par opposition à sysread) sont bufferisés par la bibliothèque C standard, pour économiser les appels systèmes. Ce n'est parfois pas désirable, par exemple lorsque l'on veut fournir une sortie caractère par caractère animée (barre de progression, etc).
On peut facilement outrepasser ce cache, par exemple pour la sortie courante (STDOUT par défaut, mais cf. select) :
$| = 1; # Autoflush = 1
Et il existe une syntaxe plus générique fonctionnant sur tous les descripteurs de fichiers, mais elle nécessite le module orienté objet :
use FileHandle; open(my $tty, ">/dev/tty"); $tty->autoflush(1);