fichiers et fonctions - Perl - Programmation
Marsh Posté le 08-12-2014 à 11:49:07
C'est le sub traitement, qui actuellement n'imprime que le nom complet, que tu dois modifier afin d'obtenir la sortie désirée par ton prof.
Un indice: jettes un œil à la fonction grep de perl, sachant que si tu as ouvert un fichier avec open(my $fh, '<', "mon_fichier" ), tu peu faire un grep /la bonne regexp/ <$fh> pour filtrer les lignes du fichier (et sachant aussi que la solution bateau attendue par ton prof sera une lecture ligne a ligne, un test (avec la même bonne regexp) pour chaque ligne et l'impression à la console si la ligne passe le test).
A+,
Marsh Posté le 11-12-2014 à 16:03:27
gilou a écrit : C'est le sub traitement, qui actuellement n'imprime que le nom complet, que tu dois modifier afin d'obtenir la sortie désirée par ton prof. |
Bonjour, J'ai réussi à obtenir ce code. Qu'en pensez vous?
Code :
|
Marsh Posté le 11-12-2014 à 19:12:03
Je pense que déjà, ça serait sympa si vous formatiez et aériez le code.
Code :
|
A+,
Marsh Posté le 12-12-2014 à 15:23:26
Je n'ai pas testé l'ensemble, mais c'est l'idée.
Quelques remarques:
- éviter les
print "\nCe programme parcourt toute l'arborescence d'un dossier que vous allez donner";
print "\nIl va afficher tous les fichiers et les sous-dossiers";
print "\nPour chaque fichier, on affichera le nom et la taille";
print "\nPour chaque fichier on recherche la correspondance d'un mot en début de ligne";
print "\nOn écrit le résultat dans le fichier Rapport.txt\n\n";
et utiliser plutôt ce style:
print "\nCe programme parcourt toute l'arborescence d'un dossier que vous allez donner\n";
print "Il va afficher tous les fichiers et les sous-dossiers\n";
print "Pour chaque fichier, on affichera le nom et la taille\n";
print "Pour chaque fichier on recherche la correspondance d'un mot en début de ligne\n";
print "On écrit le résultat dans le fichier Rapport.txt\n\n";
Ce n'est peut être pas important en Perl, mais il y a pas mal de langages ou le fait d'avoir un \n en fin de texte a afficher est significatif (ie déclenche l'affichage).
- my $D= shift @_; a remplacer par my $D= shift;
C'est la même chose, mais c'est la pratique courante, de ne pas écrire les variables implicites quand c'est évident.
idem ici:
while (my $ligne = <$FH_IN> ) { # lecture du fichier courant
if ( $ligne =~ /^$M/ ) { # recherche du motif en début de ligne
print $FH_OUT "$ligne";
}
la pratique pour ce genre de boucle simple serait plutôt d'écrire
while (<$FH_IN> ) { # lecture du fichier courant
if ( /^$M/ ) { # recherche du motif en début de ligne
print $FH_OUT $_;
}
avec la variable implicite $_
- d'autre part, réserver les majuscules aux variables globales: $FH_IN -> $fh_in
opendir (REP,$D) or die ("Impossible d'ouvrir le repertoire ",$D);
# On recupere les fichiers du descripteur REP dans @listFile
# Notez bien que @listFile peut contenir à la fois des dossiers et des fichiers
my @listFile = readdir (REP);
# on ferme le descripteur
close (REP);
Primo, l'erreur: ça doit être closedir et non pas close.
D'autre part, aucune raison de ne pas utiliser des variables locales:
opendir (my $rep, $D) or die ("Impossible d'ouvrir le repertoire ",$D);
# On recupere les fichiers du descripteur $rep dans @listFile
# Notez bien que @listFile peut contenir à la fois des dossiers et des fichiers
my @listFile = readdir ($rep);
# on ferme le descripteur
closedir ($rep);
- plutôt que faire un test complexe
elsif (-d $nomComplet and $_ ne "." and $_ ne ".." )
autant éliminer . et .. a la source:
my @listFile = grep !/^\.{1,2}$/o, readdir ($rep);
- enfin
foreach (@listFile) {
# Création du nom complet :
my $nomComplet = $D."/".$_;
# S'il s'agit d'un fichier on le traite via la fonction de traitement
if (-f $nomComplet) {
traitement($nomComplet);
}
# sinon s'il s'agit d'un dossier autre que les dossiers . et ..
elsif (-d $nomComplet) {
# ... on lance un nouvel appel récursif à notre fonction, sur ce dossier là :
AnalyseDossier ($nomComplet);
}
}
un elseif pas suivi de else, j'aime pas.
Ce serait plus simple ainsi:
foreach (@listFile) {
# Création du nom complet :
my $nomComplet = $D."/".$_;
# S'il s'agit d'un fichier on le traite via la fonction de traitement
if (-f $_) {
traitement($nomComplet);
next;
}
# sinon s'il s'agit d'un dossier autre que les dossiers . et ..
if (-d $_) {
AnalyseDossier ($nomComplet);
next;
}
}
et c'est probablement plus optimisé en faisant if (-d _) (après un premier test de fichier -f, -d, ... la variable _ contient les infos relatives au fichier, pour être réutilisée avec d'autres tests de fichier, sinon, chaque test fait un appel système fstat ou stat, ce qui est plus long)
- pensez aussi à utiliser
use autodie;
ce qui permet de remplacer
open my $FH_OUT, '>:utf8', './Rapport.txt' or die "ouverture impossible de Rapport.txt $!"; # ouverture du fichier rapport
par
open my $FH_OUT, '>:utf8', './Rapport.txt';
(bon, vérifier quand même en quelle langue sera le message d'erreur automatique dans ce dernier cas)
A+,
Marsh Posté le 12-12-2014 à 23:49:16
[quotemsg=2245900,5,19304]Je n'ai pas testé l'ensemble, mais c'est l'idée.
Quelques remarques:
- éviter les
print "\nCe programme parcourt toute l'arborescence d'un dossier que vous allez donner";
print "\nIl va afficher tous les fichiers et les sous-dossiers";
print "\nPour chaque fichier, on affichera le nom et la taille";
print "\nPour chaque fichier on recherche la correspondance d'un mot en début de ligne";
print "\nOn écrit le résultat dans le fichier Rapport.txt\n\n";
et utiliser plutôt ce style:
print "\nCe programme parcourt toute l'arborescence d'un dossier que vous allez donner\n";
print "Il va afficher tous les fichiers et les sous-dossiers\n";
print "Pour chaque fichier, on affichera le nom et la taille\n";
print "Pour chaque fichier on recherche la correspondance d'un mot en début de ligne\n";
print "On écrit le résultat dans le fichier Rapport.txt\n\n";
Ce n'est peut être pas important en Perl, mais il y a pas mal de langages ou le fait d'avoir un \n en fin de texte a afficher est significatif (ie déclenche l'affichage).
- my $D= shift @_; a remplacer par my $D= shift;
C'est la même chose, mais c'est la pratique courante, de ne pas écrire les variables implicites quand c'est évident.
idem ici:
while (my $ligne = <$FH_IN> ) { # lecture du fichier courant
if ( $ligne =~ /^$M/ ) { # recherche du motif en début de ligne
print $FH_OUT "$ligne";
}
la pratique pour ce genre de boucle simple serait plutôt d'écrire
while (<$FH_IN> ) { # lecture du fichier courant
if ( /^$M/ ) { # recherche du motif en début de ligne
print $FH_OUT $_;
}
avec la variable implicite $_
- d'autre part, réserver les majuscules aux variables globales: $FH_IN -> $fh_in
opendir (REP,$D) or die ("Impossible d'ouvrir le repertoire ",$D);
# On recupere les fichiers du descripteur REP dans @listFile
# Notez bien que @listFile peut contenir à la fois des dossiers et des fichiers
my @listFile = readdir (REP);
# on ferme le descripteur
close (REP);
Primo, l'erreur: ça doit être closedir et non pas close.
D'autre part, aucune raison de ne pas utiliser des variables locales:
opendir (my $rep, $D) or die ("Impossible d'ouvrir le repertoire ",$D);
# On recupere les fichiers du descripteur $rep dans @listFile
# Notez bien que @listFile peut contenir à la fois des dossiers et des fichiers
my @listFile = readdir ($rep);
# on ferme le descripteur
closedir ($rep);
- plutôt que faire un test complexe
elsif (-d $nomComplet and $_ ne "." and $_ ne ".." )
autant éliminer . et .. a la source:
my @listFile = grep !/^\.{1,2}$/o, readdir ($rep);
- enfin
foreach (@listFile) {
# Création du nom complet :
my $nomComplet = $D."/".$_;
# S'il s'agit d'un fichier on le traite via la fonction de traitement
if (-f $nomComplet) {
traitement($nomComplet);
}
# sinon s'il s'agit d'un dossier autre que les dossiers . et ..
elsif (-d $nomComplet) {
# ... on lance un nouvel appel récursif à notre fonction, sur ce dossier là :
AnalyseDossier ($nomComplet);
}
}
un elseif pas suivi de else, j'aime pas.
Ce serait plus simple ainsi:
foreach (@listFile) {
# Création du nom complet :
my $nomComplet = $D."/".$_;
# S'il s'agit d'un fichier on le traite via la fonction de traitement
if (-f $_) {
traitement($nomComplet);
next;
}
# sinon s'il s'agit d'un dossier autre que les dossiers . et ..
if (-d $_) {
AnalyseDossier ($nomComplet);
next;
}
}
et c'est probablement plus optimisé en faisant if (-d _) (après un premier test de fichier -f, -d, ... la variable _ contient les infos relatives au fichier, pour être réutilisée avec d'autres tests de fichier, sinon, chaque test fait un appel système fstat ou stat, ce qui est plus long)
- pensez aussi à utiliser
use autodie;
ce qui permet de remplacer
open my $FH_OUT, '>:utf8', './Rapport.txt' or die "ouverture impossible de Rapport.txt $!"; # ouverture du fichier rapport
par
open my $FH_OUT, '>:utf8', './Rapport.txt';
(bon, vérifier quand même en quelle langue sera le message d'erreur automatique dans ce dernier cas)
Bonjour,
Voici la modification, Seulement voila le fichier . txt ne se génére pas prq?
Code :
|
Marsh Posté le 13-12-2014 à 04:05:48
Oui, j'avais lu un peu trop vite le code, si tu remplaces les tests
if (-f $_) et if (-d $_)
par
if (-f $nomComplet) et if (-d $nomComplet)
ça marchera.
Habituellement, je fais un cd dans le répertoire pour utiliser directement la liste retournée par opendir
un petit conseil: remplaces le test if (-f $nomComplet) par if (-T $nomComplet) vu que seuls les fichiers texte t'intéressent.
Ou j'aurais gardé -f et testé pour -T avant ouverture du fichier si tu veux lister les fichier non texte
Notes que en Perl, un principe de base est d'utiliser les modules déjà existant.
J'aurais utilisé File::Find (use File::Find; en tête) et remplacé une partie de ton code par
Code :
|
find(\&wanted, $D); va faire un parcours récursif de $D et ses sous répertoires, et pour chaque fichier ou répertoire, il va appeler la sub wanted (on peut la renommer si on veut) avec le nom du fichier/répertoire dans $_ et son répertoire dans $File::Find::dir, et de plus, ça vire les cas de '.' et '..' automatiquement
A+,
Marsh Posté le 07-12-2014 à 22:52:23
Bonjour, j'ai une problématique face à un sujet : en effet, mon prof m'a envoyé un parcours d'une arborescence. Je ne vois pas la différence avec l'énonce. Le prof nous demande de nous servir de cette arborescence pour faire le code répondant à l'exercice.
Chercher dans un dossier donné, et ses sous-dossiers, tous les fichiers qui contiennent des lignes commençant par un mot donné et écrire dans un fichier rapport la liste des fichiers répondant au critère.
Le parcours du dossier devra se faire dans une fonction (utilisation de « sub ») distincte du reste du programme.
Le rapport sera présenté de la façon suivante :
Date : Thu Nov 7 10:01:41 2013
Dossier : /chemin/dossier
fichier1
ligne du fichier1 commençant par le mot cherché
ligne suivante du fichier1 commençant par le mot cherché
...
dernière ligne du fichier1 commençant par le mot cherché
fichier2
ligne du fichier2 commençant par le mot cherché
ligne suivante du fichier2 commençant par le mot cherché