Pourquoi est-ce que opendir, readdir, stat est si lent comparé à la commande dir de Windows?

J’ai un script Perl qui utilise opendir pour lire le contenu d’un répertoire:

 opendir ( DIR, $path ) or next; while (my $file = readdir DIR) { 

Alors je fais:

  • -s $file pour obtenir la taille de chaque fichier
  • (stat($file))[9] pour obtenir l’heure modifiée de chaque fichier

Je l’exécute depuis une machine Windows et accède à un partage Samba sur Ubuntu 14.04.

Tout fonctionne très bien, mais le processus semble très lent par rapport au moment où je lance une liste de répertoires dans le même dossier.

Est-ce que quelqu’un sait pourquoi utiliser opendir prend beaucoup plus de temps qu’un listing dir et s’il est possible de changer mon script pour l’accélérer?

Selon perlport :

Sur Win32, stat() doit ouvrir le fichier pour déterminer le nombre de liens et les atsortingbuts de mise à jour qui peuvent avoir été modifiés via des liens physiques. Définir ${^WIN32_SLOPPY_STAT} sur une valeur vraie accélère stat() en ne réalisant pas cette opération.

Étant donné que les fichiers auxquels vous accédez sont sur un partage Samba, leur ouverture demande probablement beaucoup de temps. En outre, -s crée un appel de système de stat arrière-plan, de sorte que les appels -s suivis de stat sont inutiles.

Les éléments suivants devraient être plus rapides:

 local ${^WIN32_SLOPPY_STAT} = 1; opendir my $dh, $path or die "Failed to opendir '$path': $!"; while (my $file = readdir $dh) { my ($size, $mtime) = (stat $file)[7, 9]; say join "\t", $file, $size, $mtime; } 

Dir sera beaucoup plus rapide car c’est du code binary que je soupçonne être très optimisé, donc il peut récupérer et formater l’information rapidement.

Dans votre script, il semble que vous fassiez plusieurs appels à interpréter, l’un pour l’époque et l’autre pour la taille. Même si les appels inférieurs en Perl sont des codes binarys, pour obtenir les informations, il faut probablement passer par plusieurs couches. Vous pouvez réduire le nombre d’appels par suggestion @mob en enregistrant les valeurs renvoyées par stat et en accédant aux composants dont vous avez besoin. Par exemple:

 @items = stat($file); $size = $items[7]; $modified = $items[9]; 

ce qui permettrait d’enregistrer l’un des appels et éventuellement accélérer le script.

Si vous voulez tous les fichiers, vous pouvez envisager de faire un appel système pour faire une commande de répertoire et redirect la sortie vers un fichier, après quoi vous pourrez parsingr le fichier pour obtenir les informations de temps et de taille. Cela peut être un peu plus rapide en fonction de la quantité de fichiers. (/ 4 sera une année à 4 chiffres, / t: w sera le dernier écrit / modifié et / c éliminera les virgules dans la taille)

 system("dir /4 /t:w /-c $path > tempList.txt"); 

Ensuite, ouvrez et parsingz le fichier redirigé pour obtenir les informations souhaitées.

 open my $in,"tempList.txt" die "Unable to open file tempList.txt"; my @lines = <$in>; close($in); chomp(@lines); foreach ( @lines ) { next if ( ! ( m/^\d{4}\/\d{2}\/\d{2}\s+ ); # Not a line with a file @parts = split('\s+'); # Get the parts you need (time and size, where you may have to some other # work to get it in the desired format #..... } 

Il est peut-être possible d’append des expressions rationnelles pour faire la correspondance et d’extraire les éléments lorsque vous en avez besoin lorsque vous testez si vous souhaitez traiter la ligne. Cela pourrait faire gagner du temps et des efforts.