dimanche 22 avril 2012

Chronométrer l'ouverture d'un fichier

La journée se prête aux comptes à rebours, non ? Alors parlons de mesure de temps...

Un jour j’ai développé un petit chrono en VBA pour vérifier les délais d’ouverture de fichiers sur un serveur distant. Ca fonctionne comme ceci : le programme demande de sélectionner un fichier, il teste le délai d’ouverture de ce fichier, puis affiche le résultat du test.

Le principe est simple. Après avoir localisé le fichier, il faut :
1. lancer le chrono
2. ouvrir le fichier
3. arrêter le chrono.

À ceci se sont ajoutées deux choses :
- c’est plus propre de refermer le fichier, donc autant chronométrer aussi son délai de fermeture ;
- ça peut être intéressant de faire plusieurs tests successivement, donc on va fabriquer une boucle pour ça.

Allons-y !



Préoccuppons-nous d’abord du coeur de l’opération.

Les variables dont on va avoir besoin sont :
- le nom et l’adresse  du fichier que l’utilisateur localisera par la boîte de dialogue “Ouvrir”. Appelons-la F : cette variable est nécessairement de type Variant parce que c’est un texte si l’utilisateur localise effectivement un fichier, mais un booléen (valant False) s’il quitte la boîte de dialogue qu’on va utiliser.
- les trois temps du chrono, T1, T2 et T3, qui sont des variables Single.
- les délais entre T1 et T2 (D1) et entre T2 et T3 (D2) : manipuler les temps relevés par le chrono et gérer leur format d’affichage est un tant soit peu acrobatique. On pourrait tout à fait se passer de ces variables mais elles apportent un confort dans l’écriture VBA.
- Msg pour construire le message qu’on affichera en fin de chrono.

La première chose à faire est de demander à l’utilisateur d’indiquer le fichier dont il souhaite chronométrer l’ouverture. On fait ça avec la méthode GetOpenFilename, qui affiche la boîte de dialogue “Ouvrir”. En réalité, cette méthode ne génère pas l’ouverture du fichier : elle se contente de récupérer le nom et l’adresse d’un fichier. Ensuite, on en fait ce qu’on veut !
Concrètement, ça se fait comme ceci :
    F = Application.GetOpenFilename()
On peut passer des paramètres à cette méthode, par exemple pour limiter le champ des possibles à des formats de fichier particuliers, mais aucun n’est obligatoire. Dans le cas présent on va l’utiliser comme ça.

Au pssage, dans le cas où l’utilisateur annule la boîte de dialogue (bouton “Annuler”, cette méthode renvoie la valeur False. On en tient compte pour faire ce que l’utilisateur souhaite voir se passer lorsqu’il fait ça : on arrête tout.
    If F = False Then Exit Sub

Pour les relevés de temps, on va se servir de la fonction Timer. Celle-ci donne un nombre au format Single qui correspond au nombre de secondes écoulées depuis 0h00. (Au fait, comme il y en a au maximum 86 400 – le nombre de secondes dans une journée – le format Single suffit, il n’y a pas besoin de travailler en Double.) Alors oui, si on lance le chrono à 23:59:59 et que ça met un peu de temps, le résultat sera négatif. Pour être perfectionniste, il faudrait tenir compte de ça, vérifier la ou les date(s), calculer les différences le cas échéant, etc. Ce n’est pas l’idée ici, et franchement il m’arrive rarement de devoir chronométrer des ouvertures de fichiers à minuit. Donc tenons-nous en à des relevés tout simples.

Maintenant, le coeur de la macro se trouve dans la séquence suivante :
     T1 = Timer                        ' on relève un 1° temps
     Workbooks.Open Filename:=F            ' on ouvre le fichier
     T2 = Timer                        ' on relève un 2° temps
     ActiveWorkbook.Close SaveChanges:=False    ' on ferme le fichier
     T3 = Timer                        ' on relève un 3° temps

Facile, non ? Au fait, je précise que la fermeture dans se faire sans enregistrement. Si le fichier contient des mises à jour automatique à l’ouverture ou des calculs (fonction ALEA notamment), il y aura eu des modifications dans le bref laps de temps où le fichier est ouvert, donc c’est prudent de spécifier qu’on ferme sans sauvegarder.

Ensuite, je calcule les délais par différence, et j’en profite pour rendre ces données lisibles, en millisecondes (donc en multipliant la différence par mille) et sans décimale. Comme ceci :
D1 = Format((T2 - T1) * 1000, "0")
    D2 = Format((T3 - T2) * 1000, "0")

Puis je construis le message qui annoncera à l’utilisateur le résultat du test, et je termine ce message par la question “Voules-vous faire un autre test ?”.

Enfin, j’affiche ce message en spécifiant deux paramètres de bouton : vbYesNo qui obligera l’utilisateur à répondre par oui ou non à la question, et, pour le confort, vbInformation qui rappelle qu’on a là une info. Et on recueille dans une variable la réponse cliquée par l’utilisateur.



Et la boucle évoquée plus haut ?

Elle consiste à encadrer les éléments de code qu’on vient de voir par les instructions Do ... Loop et à prévoir la sortie de boucle lorsque l’utilisateur répond “Non” à la question posée. Concrètement :
Do
''' instructions
Z = MsgBox(Msg, vbYesNo + vbInformation)
Loop Until Z = vbNo



Reste à mettre tout ça ensemble :


Sub Chrono_Ouverture()

Dim F As Variant
Dim T1 As Single, T2 As Single, T3 As Single
Dim D1 As Variant, D2 As Variant
Dim Msg As String


Do

    ' localisation du fichier
    F = Application.GetOpenFilename()
    If F = False Then Exit Sub

' coeur de la macro
Application.ScreenUpdating = False       
     T1 = Timer                        ' chrono initial
     Workbooks.Open Filename:=F            ' ouverture fichier
     T2 = Timer                        ' chrono intermédiaire
     ActiveWorkbook.Close SaveChanges:=False    ' fermeture
     T3 = Timer                        ' chrono final    
Application.ScreenUpdating = True
   
    ' durées
D1 = Format((T2 - T1) * 1000, "0")
    D2 = Format((T3 - T2) * 1000, "0")
   
    ' message
    Msg = "Fichier : " & F _
& vbCrLf _
       & vbCrLf & "Temps d'ouverture : " & D1 & " millisecondes" _
           & vbCrLf & "Temps de fermeture : " & D2 & " millisecondes" _
           & vbCrLf _
& vbCrLf & "Faire un autre test ?"
   
    Z = MsgBox(Msg, vbYesNo + vbInformation)

Loop Until Z = vbNo


End Sub

Aucun commentaire:

Enregistrer un commentaire