Formation Perl - Formateur Perl

Formation de qualité par un spécialiste Perl

Sylvain Lhullier

Version 1.5.0
avril 2024


Guide Perl - Débuter et progresser en Perl

Dernière version sur  https://formation-perl.fr/guide-perl.html
© 2002-2024 Sylvain Lhullier - Permission est accordée de copier et distribuer ce document sans modification et à condition de fournir un lien vers la page https://formation-perl.fr/guide-perl.html

> Envie d'une formation Perl ? Sylvain Lhullier propose des formations au langage Perl, contactez-le.

7. Manipulation de fichiers

Pour le moment nous avons écrit des programmes dont les interactions avec leur environnement étaient faibles. Nous allons voir dans cette partie comment manipuler des fichiers en Perl. Les fichiers se retrouvent dans tous les langages, mais la manière très simple et très puissante de les manipuler fait des fichiers une facilité de Perl.

7.1. Opérateurs sur les noms de fichier

Perl dispose d'opérateurs prenant en paramètre un nom de fichier ; ce nom de fichier doit être un scalaire (une variable ou une constante). Leur valeur de retour est souvent booléenne et quelquefois numérique. Les coutumiers du shell retrouveront de nombreuses options de la commande test.

  • -e teste si son paramètre est un chemin valable dans le système de fichiers (répertoire, fichier, etc.). On pourrait l'utiliser ainsi :

    if( -e "/usr/tmp/fichier" ) {
       print "Le fichier existe\n";
    }
    
  • -f teste si son paramètre est un fichier normal.

  • -d teste si son paramètre est un répertoire.

  • -l teste si son paramètre est un lien symbolique. Ceci n'exclut pas que -f ou -d renvoie vrai.

  • -r teste si le programme a le droit de lire le fichier/répertoire/etc passé en paramètre.

  • -w teste si le programme a le droit d'écrire.

  • -x teste si le programme a le droit d'exécuter le fichier ou d'accéder (ou axéder :-)) au répertoire.

  • -o teste si le fichier appartient à l'utilisateur qui exécute le programme.

  • -z teste si le fichier est vide.

  • -s teste si le fichier est non vide ; en fait cet opérateur renvoie la taille du fichier.

  • -M renvoie l'âge en jour du fichier (depuis le début de l'exécution du programme).

Il existe tout plein d'autres opérateurs sur les fichiers ; pour en connaître la liste complète, je vous invite à lancer la commande perldoc -f -X

Voici quelques exemples d'utilisation de ces opérateurs :

my $file = "/usr/doc/perl";
if( -f $file && -w $file ) { .... }
my $taille = -s $file;
my $age = -M $file;

Simple et efficace.

7.2. La fonction glob

La fonction glob prend en argument une expression et renvoie une liste de noms de fichiers. Cette liste correspond à l'évaluation de l'expression selon les wildcards du shell.

Par exemple, glob( '*.o' ) renvoie la liste des fichiers du répertoire courant ayant l'extension .o

Notez bien qu'il ne s'agit pas d'une expression régulière (pour ceux qui connaissent ; pour les autres, nous en parlerons plus tard), mais bien d'une expression telle qu'on la donnerait à un shell : ls [A-Z]*.h liste tous les fichiers commençant par une majuscule ayant l'extension .h

Il existe une syntaxe plus concise et au comportement identique à cette fonction : l'expression peut être mise entre chevrons. Les deux lignes suivantes effectuent la même opération :

@l = glob('/usr/include/*.h');
@l = </usr/include/*.h>;

Après l'exécution d'une de ces deux lignes, le tableau @l contient la liste des noms absolus des fichiers d'include pour le C du répertoire /usr/include

7.3. Premiers exemples

Voici un premier exemple de manipulation de noms de fichiers :

#!/usr/bin/perl
use strict;
use warnings;
foreach my $name ( glob('*') ) {
   print "$name\n"  if( -l $name );
}

Il affiche les liens symboliques du répertoire courant.

Voici un second exemple :

#!/usr/bin/perl
use strict;
use warnings;
foreach my $name ( glob('.* *') ) {
   next if( ! -d $name );
   next if( ! -w $name );
   print "$name : ". ( -s $name ) ."\n";
}

Ce programme affiche le nom et la taille des sous-répertoires du répertoire courant sur lesquels j'ai les droits d'écriture (y compris ceux commençant par un point, donc . et ..).

7.4. Ouverture de fichier

Pour lire ou écrire dans un fichier, il est nécessaire de l'ouvrir préalablement. La fonction effectuant cette opération en Perl se nomme open et sa syntaxe est la suivante : open( descripteur, mode, nom-de-fichier )

Le paramètre descripteur sera l'identifiant du fichier après ouverture (on pourrait parler de descripteur de fichier). C'est ce descripteur qui devra être fourni aux fonctions de lecture et d'écriture pour manipuler le fichier. Il s'agit d'une variable que vous devez déclarer, par exemple directement dans le open.

Le paramètre mode est un scalaire (chaîne de caractères) comportant un ou deux caractères indiquant le mode d'ouverture :

Tableau 2. 

Caractère(s)Mode d'ouverture
<lecture
>écriture (écrasement)
>>écriture (ajout)
+>lecture et écriture (écrasement)
+<lecture et écriture (ajout)

Les habitués du shell retrouveront certaines notations connues.

Par exemple open(my $fd1,'<','index.html') ouvre le fichier index.html en lecture et open(my $fd2,'>','index.html') l'ouvre en écriture-écrasement (c'est-à-dire que le fichier sera vidé avant que le curseur ne soit placé au début du fichier).

Cette fonction open renvoie une valeur booléenne vrai ou faux indiquant le bon déroulement ou non de l'opération. Il est très important de tester les valeurs de retour des fonctions manipulant les fichiers (cela est vrai, quel que soit le langage), car on ne peut jamais être sûr de rien. Voici deux exemples de tests de la valeur de retour d'open :

if( ! open($fd,'>>','data.txt') ) {
   exit(1);
}

Dans ce premier exemple, on tente d'ouvrir en ajout un fichier data.txt ; en cas d'impossibilité, on appelle la fonction exit qui met fin au programme (la valeur 1 signale une erreur ; la valeur 0 signalant la fin normale du programme, les autres valeurs sont utilisées pour signaler au shell appelant une erreur). Vous noterez que l'utilisateur qui exécute le programme n'est pas informé de la cause de l'échec ; le programme se termine, tout au plus sait-il qu'il y a eu un problème avec l'ouverture de ce fichier, mais il n'en connaît pas la cause. L'exemple suivant va nous permettre de lui afficher un joli message d'erreur :

open($fd2,'<','/tmp/$a') or die("open: $!");

Nous cherchons ici à ouvrir en lecture le fichier dont le nom serait la concaténation de la chaîne /tmp/ et du contenu de la variable $a. La fonction die met fin au programme comme exit le ferait, mais affiche en plus le paramètre qu'on lui passe. En l'occurrence, le paramètre fourni est la chaîne de caractères comportant le nom de la fonction qui cause l'échec (on aurait pu ajouter le nom du fichier) ainsi que la variable $!. En contexte de chaîne de caractères, cette variable magique $! contient le message errno de la dernière erreur survenue, par exemple No such file or directory ou Permission denied, etc. L'utilisateur est donc informé de la cause de la fin du programme.

La syntaxe open() or die(); ainsi que sa signification proviennent de l'évaluation paresseuse du or. En effet, dans l'expression (a or b) si a est vrai, il n'est pas nécessaire d'évaluer b pour connaître la valeur de l'expression. C'est ce qu'il se passe ici : si open() renvoie vrai, il n'est pas nécessaire d'évaluer die().

Les descripteurs de fichier sont d'une espèce étrange en Perl, le débutant s'abstiendra de chercher à trop comprendre les mécanismes sous-jacents. Ce que l'on pourrait dire, c'est qu'il n'est pas nécessaire de déclarer un descripteur de fichier, la fonction open valant déclaration.

7.5. Lecture, écriture et fermeture de fichier

Une fois un fichier ouvert, il nous est possible d'écrire et/ou de lire dedans (selon le mode d'ouverture) et de le fermer.

La lecture des fichiers texte s'effectue typiquement au moyen de l'opérateur chevrons, cette lecture se faisant ligne par ligne.

$l = <$fd>;

Cette instruction lit la prochaine ligne disponible du fichier FIC. Vous noterez bien que l'opérateur chevrons (diamond operator en anglais) est ici en contexte scalaire. En contexte de liste, il renvoie la liste de toutes les lignes restant dans le fichier :

@t = <$fd>;

Cette instruction « absorbe » toutes les lignes du fichier dans une liste qui est placée dans le tableau @t.

Pour itérer sur les lignes d'un fichier, il est courant de faire ainsi :

while( defined( $l = <$fd> ) ) {
   chomp $l;
   print "$. : $l\n";
}

La boucle while donne pour valeur à la variable $l une à une toutes les lignes du fichier. La fonction chomp supprime le dernier caractère s'il s'agit d'un retour à la ligne. La variable spéciale $. vaut le numéro de la ligne courante du dernier fichier lu (ici $fd).

Si vous utilisez la variable spéciale omniprésente $_, la construction

while( defined( $_ = <$fd> ) )

peut même s'abréger en :

while( <$fd> )

Pour écrire dans un fichier, nous allons utiliser les fonctions print et printf que nous avons déjà vues. Elles prennent en premier argument le descripteur de fichier :

print( $fd "toto\n" );
printf( $fd "%03d", $i );

Il faut noter qu'il n'y a pas de virgule après le descripteur de fichier (il ne faut pas en mettre !). Les parenthèses sont comme toujours optionnelles autour des arguments, mais permettent de lever certaines ambiguïtés. La fonction printf fonctionne comme printf ou fprintf du C et ne sera donc pas détaillée ici (voir man 3 printf).

Pour fermer un descripteur de fichier (et donc vider les buffers associés), il faut faire appel à la fonction close :

close( $fd );

À noter que si vous réutilisez un descripteur de fichier dans un open sans faire de close au préalable, Perl ne rouspétera pas et fermera consciencieusement le premier fichier avant d'ouvrir le deuxième.

Il existe plusieurs fichiers ouverts automatiquement par Perl dès le lancement du programme :

  • STDIN : l'entrée standard (souvent le clavier) ;

  • STDOUT : la sortie standard (souvent le terminal). Par défaut print et printf écrivent sur ce flux ;

  • STDERR : la sortie d'erreur standard (souvent le terminal). Par défaut warn et die écrivent sur ce flux ;

  • ARGV : ce descripteur est un peu spécial, mais souvent bien pratique. Les lignes lues sont celles des fichiers de la ligne de commande (donc les arguments passés au programme sont considérés comme des noms de fichier) ; si le programme est lancé sans argument, l'entrée standard est lue. N.B. Vous pouvez écrire soit <ARGV> soit <> La variable spéciale $ARGV contient le nom du fichier en cours de lecture.

Discutons un peu de la manipulation de fichiers binaires. Les exemples de lecture de fichiers donnés jusqu'ici ne conviennent pas à de tels fichiers, mais plutôt à des fichiers contenant du texte. Vous pouvez, pour cela, utiliser la fonction getc qui renvoie le prochain caractère disponible : $c = getc($fd);. Vous pouvez aussi faire usage de la fonction read qui lit un nombre déterminé de caractères : $tailleLue = read( $fd, $tampon, $tailleÀLire );. Les données seront placées dans la variable $tampon. À la fin du fichier, ou s'il y a un problème, le tampon n'est pas complètement rempli. C'est pour cela que l'on récupère la valeur de retour de read.

Pour écrire des données non textuelles dans un fichier, vous pouvez tout à fait utiliser les fonctions print et printf, car les chaînes de caractères de Perl peuvent contenir le caractère de code ASCII zéro. On notera que la fonction write existe, mais n'est pas l'inverse de read.

S'il vous est nécessaire d'utiliser les fonctions d'entrée/sortie bas niveau, voici leurs noms en Perl : sysopen, sysread, syswrite et close.

7.6. Deuxième exemple

Voici le prolongement de l'exemple donné pour les tables de hachage. Nous n'allons plus considérer que les mots sont contenus dans un tableau, mais nous allons les extraire d'un fichier.

#!/usr/bin/perl
use strict;
use warnings;
open(my $fd,"<$filename.txt") or die"open: $!";
my($line,@words,$word,%total);
while( defined( $line = <$fd> ) ) {
   @words = split( /\W+/, $line );
   foreach $word (@words) {
      $word =~ tr/A-Z/a-z/;
      $total{$word}++;
   }
}
close($fd);
foreach $word (sort keys %total) {
   print "$word a été rencontré $total{$word} fois.\n";
}

On effectue une boucle while sur les lignes du fichier. Chaque ligne est alors découpée en mots par la fonction split (\W+ correspond aux suites de caractères non alphanumériques, nous verrons cela dans la suite lorsque nous étudierons les expressions régulières). Chaque mot est mis en minuscules au moyen de l'opérateur tr (que nous expliquerons avec les expressions régulières).

7.7. Exécution de commandes avec open

Il est facile en Perl de lancer une commande shell et de récupérer sa sortie standard ou de fournir son entrée standard.

Pour lire la sortie standard d'un programme, il suffit d'utiliser la syntaxe suivante :

open(HANDLE,"commande|")

par exemple :

open(my $fd1,"ls|")
open(my $fd2,"df -HT $device|")

Les lignes lues via le descripteur de fichier ainsi créé seront celles que la commande aurait affichées à l'écran si on l'avait lancée depuis un terminal.

La syntaxe open(HANDLE,"|commande") permet de lancer une commande. Les lignes écrites dans le descripteur de fichier constitueront son entrée standard, par exemple :

open(my $fd3,"|gzip > $a.gz")
open(my $fd4,"|mail robert\@bidochon.org")

Quoi de plus simple ?


Contact © 1999-2024 formation-perl.fr
Formation Perl - Formation Perl intra entreprise - Formation Perl inter entreprise - Formateur Perl - Formateur Perl délégation
Formation Perl Formateur Perl Appartement à louer à Noisy-le-Grand Bric-à-Brac