====== 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 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")** | Ecriture avec troncature| | **open(FILE, ">>test")** | Ecriture en fin de fichier| | **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() { 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 () { print "

$_

\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 = ; # 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);