Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Ovrir/Ecrire dans plusieurs fichiers

3 réponses
Avatar
JalaL
Bonjour a tous,
Je souhaite faire un script qui ecrit pas mal de données dans plusieurs
fichiers.

J'utilise un script du style :

#traitement des données
while(...)
{
...
%data->{$file_name} = $file_content;
...
}
#enregistrement dans les fichiers
$time1 = Time::HiRes::time();
foreach $file_name (keys %data)
{
open(DATAFILE, '>>/path/to/'.$file_name);
print DATAFILE %data->{$file_name};
%data->{$file_name} = "";
close(DATAFILE);
}
$time2 = Time::HiRes::time();
$time = $time2 - $time1;
print $time;
#FIN


Normalement le programme devrait quitter apres l'affichage du temps
ecoulé de la boucle foreach. Ce qui se passe rééllement c'est que le
programme affiche 0.5s de temps d'execution (de foreach) et continue a
ecrire les fichiers sur le disque dur... et ne quitte qu'apres la fin de
l'ecriture de tous les fichiers (apres plusieures minutes).

J'ai l'impression que toutes les ecritures sur disque dur se passent en
meme temps, d'où le temps fou que cela prend.

Avez-vous une idée pour resoudre ce probleme.

3 réponses

Avatar
Paul Gaborit
À (at) Fri, 21 Sep 2007 03:20:43 +0200,
JalaL écrivait (wrote):
Je souhaite faire un script qui ecrit pas mal de données dans
plusieurs fichiers.

J'utilise un script du style :

#traitement des données
while(...)
{
...
%data->{$file_name} = $file_content;


Heu ? Ne serait-ce pas plutôt un truc du genre :

$data{$file_name} = $file_content;
...
}
#enregistrement dans les fichiers
$time1 = Time::HiRes::time();
foreach $file_name (keys %data)
{
open(DATAFILE, '>>/path/to/'.$file_name);


Ne pas oublier de tester l'ouverture, préférer la syntaxe à trois
arguments (plus sûr), utiliser un scalaire plutôt qu'un bareword pour
le filehandle et utiliser l'interpolation :

open(my $datafile, '>>', "/path/to/$file_name")
or die "Can't write '/path/to/$file_name': $!n";

print DATAFILE %data->{$file_name};
%data->{$file_name} = "";


Et là, on doit avoir :

print $datafile $data{$file_name};
$data{$file_name} = "";

Cette dernière ligne n'est pas vraiment utile (Perl ne rend pas de
mémoire au système et, dans ce script, il n'en a pas besoin ensuite).

close(DATAFILE);


On peut aussi vérifier le résultat du 'close' :

close($datafile)
or warn "Error closing '/path/to/$file_name': $!n";

}
$time2 = Time::HiRes::time();
$time = $time2 - $time1;
print $time;
#FIN


Normalement le programme devrait quitter apres l'affichage du temps
ecoulé de la boucle foreach. Ce qui se passe rééllement c'est que le
programme affiche 0.5s de temps d'execution (de foreach) et continue a
ecrire les fichiers sur le disque dur... et ne quitte qu'apres la fin
de l'ecriture de tous les fichiers (apres plusieures minutes).

J'ai l'impression que toutes les ecritures sur disque dur se passent
en meme temps, d'où le temps fou que cela prend.


A priori, si les appels à 'close' se passent bien, tout est déjà écrit
sur disque (en tous cas du point de vue de ce programme). N'y
aurait-il pas d'autres fichiers en cours d'écriture à la fin du
script ?

Ça peut aussi venir de la libération de la mémoire utilisée.

--
Paul Gaborit - <http://perso.enstimac.fr/~gaborit/>
Perl en français - <http://perl.enstimac.fr/>

Avatar
JalaL
À (at) Fri, 21 Sep 2007 03:20:43 +0200,
JalaL écrivait (wrote):
Je souhaite faire un script qui ecrit pas mal de données dans
plusieurs fichiers.

J'utilise un script du style :

#traitement des données
while(...)
{
...
%data->{$file_name} = $file_content;


Heu ? Ne serait-ce pas plutôt un truc du genre :

$data{$file_name} = $file_content;
...
}
#enregistrement dans les fichiers
$time1 = Time::HiRes::time();
foreach $file_name (keys %data)
{
open(DATAFILE, '>>/path/to/'.$file_name);


Ne pas oublier de tester l'ouverture, préférer la syntaxe à trois
arguments (plus sûr), utiliser un scalaire plutôt qu'un bareword pour
le filehandle et utiliser l'interpolation :

open(my $datafile, '>>', "/path/to/$file_name")
or die "Can't write '/path/to/$file_name': $!n";

print DATAFILE %data->{$file_name};
%data->{$file_name} = "";


Et là, on doit avoir :

print $datafile $data{$file_name};
$data{$file_name} = "";

Cette dernière ligne n'est pas vraiment utile (Perl ne rend pas de
mémoire au système et, dans ce script, il n'en a pas besoin ensuite).

close(DATAFILE);


On peut aussi vérifier le résultat du 'close' :

close($datafile)
or warn "Error closing '/path/to/$file_name': $!n";

}
$time2 = Time::HiRes::time();
$time = $time2 - $time1;
print $time;
#FIN


Normalement le programme devrait quitter apres l'affichage du temps
ecoulé de la boucle foreach. Ce qui se passe rééllement c'est que le
programme affiche 0.5s de temps d'execution (de foreach) et continue a
ecrire les fichiers sur le disque dur... et ne quitte qu'apres la fin
de l'ecriture de tous les fichiers (apres plusieures minutes).

J'ai l'impression que toutes les ecritures sur disque dur se passent
en meme temps, d'où le temps fou que cela prend.


A priori, si les appels à 'close' se passent bien, tout est déjà écrit
sur disque (en tous cas du point de vue de ce programme). N'y
aurait-il pas d'autres fichiers en cours d'écriture à la fin du
script ?

Ça peut aussi venir de la libération de la mémoire utilisée.

Merci pous les commentaires. Je crois que j'ai trouvé la source du

probleme, quand le programme tourne pour la premiere fois, il peut
ecrire les données traitées dans 10000 fichiers differents (apres les
avoir créés) en quelques secondes. Mais dès qu'il tourne une 2eme fois,
il met beaucoup plus de temps, certainement a cause des operations liées
a l'ajout de données : ouvrir, trouver la fin du fichiers, ajouter les
données, fermer.

Est ce qu'il y a un moyen plus efficace et plus rapide pour ajouter des
données dans des fichiers (deja existants ou pas) ?

P.S.
Le programme ajoute en moyenne quelques dixaines de Ko a la fois dans
chaque fichier.
Les fichiers sont groupés dans une arborescence organisée et sont (en
theorie) faciles a trouver.


Avatar
Paul Gaborit
À (at) Sat, 22 Sep 2007 02:44:20 +0200,
JalaL écrivait (wrote):
Merci pous les commentaires. Je crois que j'ai trouvé la source du
probleme, quand le programme tourne pour la premiere fois, il peut
ecrire les données traitées dans 10000 fichiers differents (apres les
avoir créés) en quelques secondes. Mais dès qu'il tourne une 2eme
fois, il met beaucoup plus de temps,


Je ne vois pas vraiment le rapport avec le problème que vous évoquiez
précédement... mais si ça marche bien la première fois, ça doit
pouvoir bien marcher les suivantes ! ;-)

[...] certainement a cause des operations liées a l'ajout de données :
ouvrir, trouver la fin du fichiers, ajouter les données, fermer.


A priori, l'ajout de données en fin de fichier n'est pas plus longue
que l'écriture initiale... sauf si vous utilisez un filesystem
spécial.

Est ce qu'il y a un moyen plus efficace et plus rapide pour ajouter
des données dans des fichiers (deja existants ou pas) ?


Le mode 'append' est fait pour ça :

open my $filehandle, ">>", "/chemin/du/fichier"
or die "Can't append to file '/chemin/du/fichier': $!n";

Que le fichier existe ou non, ça fonctionnera de la même manière : les
données seront ajoutées à la fin du fichier (qui sera créé si besoin
est).

--
Paul Gaborit - <http://perso.enstimac.fr/~gaborit/>
Perl en français - <http://perl.enstimac.fr/>