REM ============================================================ REM Fichier : dir_longest_path.vbs REM Desc : recherche les plus longs chemins dans une arborescence (utilisation de dir et sort) REM Année : 2009 REM Auteur : X. Gangand REM a faire : rediriger les erreurs vers un fichier (2>...) quand on lance le dir REM ============================================================ '********** Liste des procédures et fonctions ********** 'Sub Main Procédure principale'Sub Scanner1(sDossier) 'Sub DelFileIfExists Supprimer un fichier s'il existe 'Sub EnleverSautLigneFinal Enlever le vbCrLf final d'un fichier 'Sub GetPath_Lengths Analyser les fichiers issus de la commande dir 'Function LesPlusLongs Générer le code des tables HTML pour les 50 plus ongs D+F 'Sub ScannerDossier Lancer recherche dossiers et fichiers 2 'Sub SaveToFile Sauvegarde un texte dans un fichier 'Function ShellRun Lancer une commande Run de l'object Shell '********** Fin liste procédures fonctions ********** Option Explicit Const OUTPUT_FILE = "dir_longest_path.htm" Const MAX_DISPLAY = 25 'valeur à changer si on veut afficher plus de longs chemins Dim gHTML, gHTML_recap Main Sub Main REM ========================================== REM Procédure principale REM ========================================== If Wscript.Arguments.Count = 0 Then Msgbox "Passer un/des dossiers en arguments (exemple : c:\ d:\)" Wscript.Quit(0) End If Wscript.Echo "Recherche des plus longs chemins dans les dossiers spécifiés." Dim sAdvice sAdvice = _ "<br>Il arrive parfois qu'un fichier/dossier devienne inaccessible" & vbcrlf & _ "<br>Ceci peut être dû à une arborescence trop longue en amont de ce fichier/dossier." & vbcrlf & _ "<br>(pour le rendre de nouveau accessible, renommer un ou plusieurs dossiers <b>en amont</b>)" & vbcrlf & _ "<br>Cet utilitaire vous aide à repérer les longs dossiers." & vbcrlf & _ "<br><br>" 'init code HTML gHTML = _ "<html> " & vbcrlf & _ "<body bgcolor=#FFFCB1>" & vbcrlf & _ "<hr>" & vbcrlf & _ "<center>" & vbcrlf & _ "<h2>Recherche des plus longs chemins dans une arborescence</h2>" & vbcrlf & _ "<i>Utilisation des commandes internes dir et sort</i>" & vbcrlf & _ "<hr>" & vbcrlf & _ "<br>" & vbcrlf & _ "<br>" & vbcrlf & _ sAdvice & vbcrlf & _ "</center>" & vbcrlf & _ "[[gHTML_recap]]" gHTML_recap = "<center><table border=10>" & vbcrlf & _ "<tr> <td> <b>Dossier</b></td>" & vbcrlf & _ " <td align=right><b>Nb Sous-dossiers</b></td>" & vbcrlf & _ " <td align=right><b>Plus long path</b></td>" & vbcrlf & _ " <td align=right><b>Nb fichiers</b></td>" & vbcrlf & _ " <td align=right><b>Plus long path</b></td>" & vbcrlf & _ "</tr>" 'scanner chjaque dossier de la ligne de commande Dim i, oFSO, tArg Set oFSO = CreateObject("Scripting.FileSystemObject") Set tArg = Wscript.Arguments For i = 0 To Wscript.Arguments.Count-1 If oFSO.FolderExists(tArg(i)) Then Scanner1 tArg(i) Next 'finaliser le code HTML gHTML = _ gHTML & vbcrlf & _ "</body> " & vbcrlf & _ "</html>" gHTML_recap = _ gHTML_recap & "<table> </center> <br> <br> <br> " 'sauvegarder les résultats gHTML = Replace(gHTML, "[[gHTML_recap]]", gHTML_recap) SaveToFile gHTML, OUTPUT_FILE Wscript.Echo vbcrlf & "Résultats enregistrés dans le fichier " & OUTPUT_FILE & "." 'ménage DelFileIfExists "directories.tmp" DelFileIfExists "files.tmp" DelFileIfExists "u_numerote.txt" DelFileIfExists "u_numerote_sorted.txt" End Sub Function CountLines(sFile) REM ========================================= REM Compter le nombre de lignes d'un fichier REM ========================================= Dim ofso_cl, f, n Set ofso_cl = CreateObject("Scripting.FileSystemObject") Set f = ofso_cl.OpenTextFile(sFile) Do f.SkipLine n = n + 1 Loop Until f.AtEndOfStream CountLines = n End Function Function LesPlusLongs(sDossier, les50d, les50f) REM ========================================== REM Générer le code des tables HTML pour les 50 plus ongs D+F REM ========================================== LesPlusLongs = vbcrlf & _ "<br><br>" & vbcrlf & _ "<table border=5>" & vbcrlf & _ "<tr><td colspan=3 align=middle><b>Dossiers de " & sDossier & "</b></td></tr>" & vbcrlf & _ " <td><b>N°</b></td>" & vbcrlf & _ " <td><b>Long.</b></td>" & vbcrlf & _ " <td><b>Dossier</b></td>" & vbcrlf & _ "</tr>" & vbcrlf & _ CreerCorpsTableau (les50d) & vbcrlf & _ "</table>" & vbcrlf & _ "<br>" & vbcrlf & _ "<br>" & vbcrlf & _ "<br>" & vbcrlf & _ "<table border=5>" & vbcrlf & _ "<tr><td colspan=3 align=middle><b>Fichiers de " & sDossier & "</b></td></tr>" & vbcrlf & _ " <td><b>N°</b></td>" & vbcrlf & _ " <td><b>Long.</b></td>" & vbcrlf & _ " <td><b>Dossier</b></td>" & vbcrlf & _ "</tr>" & vbcrlf & _ CreerCorpsTableau (les50f) & vbcrlf & _ "</table><br><br>" End Function Function CreerCorpsTableau(g) REM ========================================== REM Ajouter un point-virgule entre le nombre 0001, 0254, ... REM et le nom complet du dossier/fichier REM ========================================== Dim tt, i, Zebre, sSep, b, j, sLongueur sSep = "|" tt = Split(g, vbcrlf) For i = LBound(tt) To UBound(tt) sLongueur = Left(tt(i),4) Do If Left(sLongueur,1) = "0" Then sLongueur = Right(sLongueur, Len(sLongueur) - 1) Else Exit Do End If Loop Zebre = sLongueur & sSep & Right(tt(i), Len(tt(i))-4) 'mettre en gras un élément sur deux 'dans l'ensemble délimité par \ b = Split(Zebre, "\") Zebre = b(0) For j = 1 To UBound(b) If j Mod 2 = 1 Then Zebre = Zebre & "\" & "<font color=blue>" & b(j) & "</font>" Else Zebre = Zebre & "\" & b(j) End If Next tt(i) = "<font size=-1>" & Zebre & "</font>" Next CreerCorpsTableau = Tab2HTML(tt, sSep, "rr") End Function Sub DelFileIfExists(sFile) REM ================================== REM = Supprimer un fichier s'il existe REM ================================== On Error Resume Next Dim oFSOdf Set oFSOdf = CreateObject("Scripting.FileSystemObject") If oFSOdf.FileExists(sFile) Then oFSOdf.DeleteFile sFile End If End Sub Sub GetPath_Lengths(sFile, nb, sLongest, les50plus_longs) REM ========================= REM Analyser les fichiers issus de la commande dir REM les50plus_longs est une chaine avec des sauts de ligne pour séparer chaque élément REM nb est read-only REM ========================= Dim tout, u, i, n 'reconstruire le tableau ajouter la longueur en tête de chaque ligne tout = FileReadAll(sFile) u = Split(tout, vbCrLf) For i = LBound(u) To UBound(u) n = Len(u(i)) n = String(4-Len(Len(u(i))), "0") & Len(u(i)) & u(i) u(i) = n Next 'trier avec la aommnde sort (beaucoup plus rapide que QSort_Simple) SaveToFile Join(u, vbcrlf), "u_numerote.txt" ShellRun "cmd /c sort < u_numerote.txt", "u_numerote_sorted.txt" EnleverSautDeLigneFinal "u_numerote_sorted.txt" u = Split(FileReadAll("u_numerote_sorted.txt"), vbCrLf) 'initialiser pour éviter de retrouver le saut de ligne en début (=ligne vide qui pose problème après) les50plus_longs = u(UBound(u)) 'ATTENTION : problème pour dossier très petit For i = UBound(u)-1 To UBound(u)-(MAX_DISPLAY-1) Step - 1 les50plus_longs = les50plus_longs & vbcrlf & u(i) Next sLongest = u(UBound(u)) End Sub Sub Scanner1(sDossier) REM ========================================== REM Traiter un dossier de la ligne de commande REM ========================================== 'pour chaque dossier traité, l'ajouter dans le sommaire 'afficher 5 colonnes : dossier , nb sous-dossiers, nombre de fichiers, plus long chemin dossier, plus long chemin fichier Dim les50f, les50d, nbd, nbf, sLongestPathD, sLongestPathF Wscript.Echo "" ScannerDossier sDossier, "dossiers", "directories.tmp", nbd ScannerDossier sDossier, "fichiers", "files.tmp", nbf Wscript.Echo "" GetPath_Lengths "directories.tmp", nbd, sLongestPathD, les50d GetPath_Lengths "files.tmp", nbf, sLongestPathF, les50f Wscript.Echo nbd & " dossiers, " & nbf & " fichiers trouvés." 'tabeau récapitulatif gHTML_recap = gHTML_recap & vbcrlf & _ "<tr> <td>" & sDossier & "</td>" & vbcrlf & _ " <td align=right>" & FormatNumber(nbd,False,,,True) & "</td>" & vbcrlf & _ " <td align=right>" & Len(sLongestPathD)-4 & "</td>" & vbcrlf & _ " <td align=right>" & FormatNumber(nbf,False,,,True) & "</td>" & vbcrlf & _ " <td align=right>" & Len(sLongestPathF)-4 & "</td>" & vbcrlf & _ "</tr>" REM les50d est une chaine avec des sauts de ligne pour séparer chaque élément REM les50f est une chaine avec des sauts de ligne pour séparer chaque élément gHTML = gHTML & vbcrlf & _ LesPlusLongs (sDossier, les50d, les50f) End Sub Function Tab2HTML(t, sSep, sPosition) REM ========================================== REM Transforme un tableau VBS en tableau HTML REM Le tableau t contient des lignes, dont les éléments sont séparés par sSep REM ========================================== Dim i, u, j For i = LBound(t) To UBound(t) Tab2HTML = Tab2HTML & vbcrlf & " <tr>" u = Split(t(i), sSep) Tab2HTML = Tab2HTML & vbcrlf & " <td align=middle><font size=-1>" & i+1 & "</font></td>" For j= 0 To UBound(u) Tab2HTML = Tab2HTML & vbcrlf & " <td aligne=middle>" & u(j) & "</td>" Next Tab2HTML = Tab2HTML & vbcrlf & " </tr>" Next End Function Sub ScannerDossier (Dossier, sType, sReportFile, nb) REM ========================================= REM Lancer recherche dossiers et fichiers 2 REM Attention : la commande dir ajoutre un saut de ligne à la dernière ligne REM ========================================= Wscript.Echo "Recherche des " & sType & " dans " & Dossier & " ..." Select Case sType Case "dossiers" : ShellRun "cmd /c dir """ & Dossier & """ /ad /s /b ", sReportFile Case "fichiers" : ShellRun "cmd /c dir """ & Dossier & """ /a-d /s /b ", sReportFile End Select 'enlever le CRLF de fin de fichier EnleverSautDeLigneFinal(sReportFile) nb = CountLines(sReportFile) End Sub Sub EnleverSautDeLigneFinal(sFile) REM ========================================= REM Enlever le vbCrLf final d'un fichier REM ========================================= Dim tout tout = FileReadAll(sFile) If Right(tout, Len(vbcrlf)) = vbcrlf Then tout = Left(tout, Len(tout) - Len(vbCrLf)) SaveToFile tout, sFile End If End Sub Function FileReadAll(sFile) REM ======================================== REM = Renvoie le contenu complet d'un fichier texte REM ======================================== On Error Resume Next Dim f, oFSOstf Set oFSOstf = CreateObject("Scripting.FileSystemObject") Set f = oFSOstf.OpenTextFile(sFile) If Err Then Msgbox "Erreur de lecture du fichier " & sFile & vbCrLf & "Fin du programme." WScript.Quit(0) End If FileReadAll = f.ReadAll Set f = Nothing Set oFSOstf = Nothing End Function Sub SaveToFile (sTexte, sFile) REM ======================================== REM = Sauvegarde un texte dans un fichier REM ======================================== Dim oFSOstf, f1 Set oFSOstf = CreateObject("Scripting.FileSystemObject") Set f1 = oFSOstf.CreateTextFile(sFile) f1.Write sTexte f1.Close Set f1 = Nothing Set oFSOstf = Nothing End Sub Function ShellRun(sCmd, sOutputFile) REM =========================================== REM = Lancer une commande Run de l'object Shell REM = vers le fichier sOutputFile (synchrone) REM = ATTENTION : toujours vérifier cmd /c !!! REM =========================================== Dim oShell Set oShell = CreateObject("Wscript.Shell") ShellRun = oShell.Run(sCmd & " > " & sOutputFile, 0, True) '0 = '1 = Activates and displays a window 'true = bWaitOnReturn, Boolean value 'indicating whether the script should 'wait for the program to finish executing 'before continuing to the next statement in your script. Set oShell = Nothing End Function