Ceci est une page optimisée pour les mobiles. Cliquez sur ce texte pour afficher la vraie page.

XL 2016 Comment passer une information entre procédure par une variable

TaigaLupus

XLDnaute Nouveau
Bonjour à tous,

j'ai recuperé ce code du grand (Boisgontier Jacques) :

Sub TousLesDossiers(LeDossier$, Idx As Long)
Dim fso As Object, Dossier As Object
Dim sousRep As Object, Flder As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Set Dossier = fso.GetFolder(LeDossier)
'examen du dossier courant
For Each Flder In Dossier.subfolders
Idx = Idx + 1
Cells(Idx, 1).Value = Flder.Path
Next
'traitement récursif des sous dossiers
For Each sousRep In Dossier.subfolders
TousLesDossiers sousRep.Path, Idx
Next sousRep
Set fso = Nothing
End Sub
'fs
Sub test()
TousLesDossiers "D:\LUI\Developement\VB_VBA\", 0
End Sub

j'aimerais au lieu d'ecrire l'adresse manuellement (celle en vert) mettre a la place une variable contenant un chemin enregistré au préalable :

CheminFichierDépart = Workbooks(ActiveWorkbook.Name).Path

je vous avoue que j'ai testé c'es deux cas mais aucun ne marche :

TousLesDossiers CheminFichierDépart, 0 " la le programme stop directe
TousLesDossiers "CheminFichierDépart", 0 " la le programme passe a la procedure ("Sub TousLesDossiers(LeDossier$, Idx As Long)") et stop a la ligne : Set Dossier = fso.GetFolder(LeDossier)

si vous aviez une idée je suis preneur, merci d'avance
 
Solution
re bonsoir
j'aimerais au lieu d'ecrire l'adresse manuellement (celle en vert) mettre a la place une variable contenant un chemin enregistré au préalable :
j'avoue que même si ça avait été codé correctement( corrigé par mes camarades) je ne comprends pas la relation avec un self path et un chemin enregistré préalablement quelque part c'est quoi le rapport
CheminFichierDépart = Workbooks(ActiveWorkbook.Name).Path
peut être voulais tu dire automatiquement le même dossier de départ que le classeur lui même
au quel cas c'est bien thisworkbook.path


faut pas oublier que FSO est aussi lourd que facile à utiliser contrairement à (DIR)qui est plus complexe a mettre en récurif dans une sub ou...

sylvanu

XLDnaute Barbatruc
Supporter XLD
Bonsoir TaigaLupus,
Normalement "TousLesDossiers CheminFichierDépart, 0" devrait marcher si le chemin est correct.
testez :
VB:
Sub test()
    CheminFichierDépart = Workbooks(ActiveWorkbook.Name).Path
    MsgBox "Le chemin devrait être :   D:\LUI\Developement\VB_VBA\" & Chr(10) & _
    "Celui tranféré est : " & CheminFichierDépart
    TousLesDossiers CheminFichierDépart, 0
End Sub
Il est possible qu'il manque un "\" à la fin. Dans ce cas faites :
Code:
CheminFichierDépart = Workbooks(ActiveWorkbook.Name).Path & "\"
 

patricktoulon

XLDnaute Barbatruc
re bonsoir
j'aimerais au lieu d'ecrire l'adresse manuellement (celle en vert) mettre a la place une variable contenant un chemin enregistré au préalable :
j'avoue que même si ça avait été codé correctement( corrigé par mes camarades) je ne comprends pas la relation avec un self path et un chemin enregistré préalablement quelque part c'est quoi le rapport
CheminFichierDépart = Workbooks(ActiveWorkbook.Name).Path
peut être voulais tu dire automatiquement le même dossier de départ que le classeur lui même
au quel cas c'est bien thisworkbook.path


faut pas oublier que FSO est aussi lourd que facile à utiliser contrairement à (DIR)qui est plus complexe a mettre en récurif dans une sub ou fonction

hahhh! on y viens
une sub ou fonction récursive à ça c'est une bonne idée
sauf que quand elle n'est pas bien mis en place et bien c'est compliqué
et justement avec FSO le gros lourdo on a là un exemple parfait

pour commencer je dirais que l'exemple donné par @TaigaLupus
issue des tutos de notre regretté Jacques Boigontiers est a but école(un principe de base )
et non une macro prête à l'emplois et optimisée pour/et en toute les circonstance


les pièges d'une sub ou fonction récursive avec FSO
les variables a transporter dans le looping (début macro/rappel macro) dans l'exemple ici présent je parle de la variable idx

des variables (ET là c'est important ) qui au mieux !!!sont chargées a chaque tour
comme le gros lourdo(vous voyez du quel je parle) mais PAS DECHARGEE !!!! même si vous avez un is nothing en fin de macro

et oui c'est là ou le bas blesse

IL FAUT SAVOIR ;une fonction récursive avec FSO commençant sur un dossier tourne autant de fois que de dossier et sous dossier ET REVIENT A SON POINT DE DÉPART !!!!!et non successivement d'un dossier à l'autre
concrètement ça se représente comment
imaginons un dossier du nom de "toto"
dans ce dossier il y a 2 dossiers titi et grosminet
dans ces deux sous dossiers j'ai deux autres sous dossiers
dans titi j'ai riri et fifi et dans grosminet j'ai loulou et bidule

disons que je schématise


alors comment ça marche
et bien en fait

chaque cession de la sub reste ouverte!!!!!!
TANT QUE LA SESSION SUIVANTE N A pas FINI QUI ELLE MÊME RESTE OUVERTE TANT QUE SA SUIVANTE N a pas fini

toto trouve titi et grosminet deux autres cessions
quand titi ou grosminet est lancé toto n'est pas fermée puis que c'est elle qui a fait le
rappel
il faut qu'elle attende donc que l'instance de la macro pour titi et gros minet soit finie
et elle va attendre longtemps puisque ces deux dernières lancent a leur tour
riri et fifi d'un coté et loulou et bidule de l'autre

on est donc quand on en est au plus profond de l'arborescence

à 5 créations ouverte de FSo sur les derniers sous dossier
en effet quand on est dans bidule forcement loulou est fini et pareil pour son cousin a gauche
imaginez vous une arborescence de 10 sous dossier fois 10 sous dossiers

et malgré tout ça le gros lourdo de FSO ne perd pas un grame

concrètement comment corriger le problème

et bien pour commencer le FSO
le FSO sera une variable public ou globale module
il sera instancié uniquement si il est nothing(une seule fois!!) pour tout la tournée
on le décharge quand vraiment la sub a fini ( avec un pointeur de fin )


on a donc une seule instance de l'object ben là mon procc se sent mieux et la mémoire aussi

ensuite
4° on envoie la liste cellule par cellule alors que l'on pourrait charger la liste dans une variable tableau pour la décharger à la fin
mais comment garder en mémoire la liste
et bien comme je disais plus haut on a la solution de balader les variable de la même manière que idx
sauf que si on a des tris ou modif a faire ça deviens vite la bérésina

alors on opte pour des variable static
elle ont l'avantage d’être déclarée dans la sub tout en restant chargées entre les tours de looping récursif

alors concrètement comment pointer le début et la fin ???
être ou ne pas être tel est la question

et bien c'est simple on en a un déjà avec idx=0 au départ
oui mais on sait pas combien il y a de dossiers on ne sait donc pas quand ça va s’arrêter

et bien sur que si on le sait !!!!!!!!
rappelez vous je cite ce que je vous ai dis plus haut
IL FAUT SAVOIR ;une fonction récursive avec FSO commençant sur un dossier tourne autant de fois que de dossier et sous dossier ET REVIENT AS ON POINT DE DEPART !!!!!et non successivement d'un dossier à

alors on peut faire quoi avec ça ??
ben c'est tout simple
en fin de sub
si idx>0 and ledossier = le first dossier ben ça veux dire que notre gros lourdo de fso a fini
quand on a ces deux conditions ,on est sur à 100% que toute l’arborescence a été visité sauf erreur dossier protégé ou System et même là!!!! l'erreur 52 et 72 se gère facilement

alors voilà la sub récursive tel que je la conçoit
1 FSO déclaré en haut de module

2 on met le idx en argument optional on peut donc omettre d'envoyer l'argument au départ

3 on créé 2 variable static
tbl() notre variable array
firsdossier le pointeur string du premier dossier de départ

4 correction de dernier shach sur le nom du dossier

5 création de l'instance fso si = nothing

6 on instancie le getfolder le dossier qui va être examiné

7° on boucle sur les dossiers enfants du dossier courant et on stocke dans l'array redimensionné dynamiquement

8 on boucle sur les sub folder et on rappelle la sub avec idx a jour

et ca tourne etc...........

9 en fin de sub (avant le "end sub"
si idx>0 and ledossier =firstdossier "
on envoie larray transposé dans la feuille
on peut vider toute les variables

terminé tout le monde descends

terminé le blablabla
VB:
Dim FSO As Object    'variable globale en haut de module

Sub TousLesDossiers(LeDossier, Optional Idx As Long = 0)
    Dim Dossier As Object, sousRep As Object, Flder As Object
    Static tbl(): Static FirstDossier$    ' les  variables tableau  et string firstdossier se charge et reste chargée tant que ca tourne

    'si on oublie le dernier slash ou des le 2d tour qui n'envoie que le path(""!! sousRep.Path !!"")
    If Right(LeDossier, 1) <> "\" Then LeDossier = LeDossier & "\"

    If Idx = 0 Then
        Erase tbl                                                               'on eraze le tableau pour une future utilisation
        FirstDossier = LeDossier                                                'on memorise le dossier de départ (on va s'en servir de pointeur de fin )
        Debug.Print LeDossier                                                   'on le pointe dans la console pour visualiser le principe
    End If

    If FSO Is Nothing Then
        Set FSO = CreateObject("Scripting.FileSystemObject")                    'on ne créée qu'une fois!!!!!!!! l'object pour economiser une cration a chaque visite d'un dossier ou soudossier
    End If

    Set Dossier = FSO.GetFolder(LeDossier)                                      'on détermine dans FSO le getfolder

    'c'est parti!!!
    For Each Flder In Dossier.subfolders                                        'examen du dossier courant
        Idx = Idx + 1: ReDim Preserve tbl(1 To Idx): tbl(Idx) = Flder.Path      'redimensionnement auto et inscription dans la variable tableau (tbl)du dossier en cours d'examen
    Next

    'traitement récursif des sous dossiers
    For Each sousRep In Dossier.subfolders
        TousLesDossiers sousRep.Path, Idx
    Next sousRep

    'ici on test si idx est > 0 et que ledossier est bien revenu  à Firsdossier(le dossier de départ )
    'si oui on transfert alors le tableau sinon on continue le looping
    If Idx > 0 And LeDossier = FirstDossier Then
        Debug.Print LeDossier
        [A:A].ClearContents
        [A1].Resize(UBound(tbl)) = Application.Transpose(tbl)
        Firsdossier = ""
        Erase tbl
        Set FSO = Nothing
    End If
End Sub

Sub test()
    TousLesDossiers "E:\vba excel"    'mettre votre dossier avec ou sans le dernier slash on s'en fou c'est corrigé dans la sub
End Sub
démonstration

à ben oui c'est plus rapide d'un coup




j'ai bien travailler moi je m'en vais me collationer dans la poire quelque victuaille satisfaisant mon appetit
a plus
 
Dernière édition:

TaigaLupus

XLDnaute Nouveau
Merci beaucoup et pour la reponse et pour la rapidité
 

TaigaLupus

XLDnaute Nouveau
Bonjour, vraiment merci , par contre j'en ai pour la semaine a tous comprendre ton post. sinon mon but et de lister les sous dossier et d'ouvrir le fichier excel contenu dans des dossier ayant toujours le même noms et ensuite de recuperer les données d'un onglet du fichier excel dans un registre...mais autant sur excel classique je suis bon (si si ) autant je bidouille sur vba.... donc un grand merci pour toutes ces explications
 

patricktoulon

XLDnaute Barbatruc
Bonjour
dans ce cas là tu a la possibilité de lister uniquement les noms de fichier directement
et toujours en récursif et on peut même argumenter juste la partie d'un nom sie les dit fichier ont un prefixe identique mais que la fin du nom est différente

après comme je l'ai plus ou mins dit attention avec fso il faut les garde fou du genre la correction du dernier slash
il faudrait aussi inclure les erreur 52 53 72 du au fichier avec nom trop long et ou avec des caractères particuliers

DuDU et moi avons mis au point justement une fonction list avec FSO gérant tout ca

tiens la voila la fso récursive sur fichiers
VB:
'**************************************************************
'fonction récursive pour lister les fichiers d'un disque ou dossier
'Utilisation de filesystemobject(FSO)
'-------------------------------------
'                          THEME
'recherche D 'amelioration  pour la lenteur de FSO en récursif
'recherche des moyens de controler les erreurs du aux noms trop long  ou fichiers interdit  ou system ou caracteres particuliers
'------------------------------------

'Auteurs Dudu2 et patricktoulon  sur exceldownload
'version 1.5
'Date:08/02/2021
'mise en place du principe (Part name) valable aussi pour (si juste extension demandée:ex;[*.XXX])
'suppression du stockage des erreurs et des msgbox d'erreur
'suppression commentaires
'utilisation d'une fonction de transposition de l'array simplifiée (horizontal(1 dim) To vertical(2 dim))pour palier au limite de la fonction transpose d'excel

'Date:08/02/2021
'accélération du processus
'en ajoutant du test dir non bloquant pour zapper les dossiers
'ne contenant pas de fichier avec l'extension ou la partie du nom demandée
'Date:13/02/2021
'remplacement du bloc  <<if takeit>> par un jumping (etiquette "ScanFolder")
'pour jumper directement sur la boucle des dossiers on  zappe directement la partie du code boucle ofile si pas de fichier
'****************************************************************
Option Explicit
Option Compare Text
Function TransposeArray(arr) ' fonction de transposition pour palier au limites de la fonction transpose d'excel
    Dim tbl(), I&: ReDim tbl(LBound(arr) To UBound(arr), 1 To 1)
    For I = LBound(arr) To UBound(arr): tbl(I, 1) = arr(I): Next
    TransposeArray = tbl
End Function
'

Function FSO_List_FICHIERS2(ByVal Folder As Variant, Optional PartName As String = "") As Variant
    Static tbl() As String: Static NbFichiers As Long: Static oFSO As Object
    Dim oDir As Object, oSubDir As Object, oFile As Object, First_Call As Boolean, TakeIT As Boolean

    If TypeOf Folder Is Object  Then                            'si ce nest pas le premier appel  Foler est un objet folder membre de FSO
        First_Call = False                                      'si ce nest pas le premier appel  on positionne First_Call a false des les 2d appel
        Set oDir = Folder                                       'si ce nest pas le premier appel  Odir est donc un object Folder membre de FSO
    Else                                                        'si c'est le premier appel Folder est de type string
        First_Call = True                                       'si c'est le premier appel first_call est a true
        Erase tbl                                               'si c'est le premier appel on eraze la variable tableau  <<tbl>>
        NbFichiers = 0                                          'si c'est le premier appel on met la variables NbFichiers à 0
        Set oFSO = CreateObject("Scripting.FileSystemObject")   'si c'est le premier appel on créée l'object FSO
        If Right(Folder, 1) <> "\" Then Folder = Folder & "\"   'si c'est le premier appel si le slach de fin on l'ajoute
        Set oDir = oFSO.getfolder(Folder)                       'si c'est le premier appel on instruit l'object Folder<<Odir>>avec le string du dossier
    End If

    TakeIT = True                                               'on met la variable Takeit à true d'office
    ' on ouvre une gestion d'erreur globale (pour les permissions refusées ou les noms portants des caracteres speciaux)
    'la gestion est valable aussi pour la boucle subFolder elle es fermé a chaque fin d'appels récursifs
    On Error Resume Next
    If Len(PartName) > 0 Then TakeIT = Len(Dir(oDir.Path & "\" & PartName)) > 0    'si partname demandé on test de presence de (fichier avec PartName dans le nom) dans le dossier en une seule fois
    If Err.Number <> 0 Or TakeIT = False Then Err.Clear:  GoSub Scanfolder ' si erreur ou TakeIt =false on zappe l'exploration des fichiers on va directement à l'exploration des sous dossiers avec gosub
 
  
    For Each oFile In oDir.Files            'boucle sur les fichiers
        If Err.Number = 0 Then              'si pas d'erreur
            If Len(PartName) = 0 Then       'si pas de PartName demandé on memorise le fichier directement
                NbFichiers = NbFichiers + 1: ReDim Preserve tbl(1 To NbFichiers): tbl(NbFichiers) = oFile.Path
            Else                            'si PartName demandé on teste si le nom de fichier like PartName
                If oFile.Name Like PartName Then NbFichiers = NbFichiers + 1: ReDim Preserve tbl(1 To NbFichiers): tbl(NbFichiers) = oFile.Path                'Stocke le nom complet du fichier en table
            End If
        End If
        Err.Clear                                       ' on clear l'erreur au cas ou
    Next oFile

Scanfolder:                                             ' etiquette du jumping d'exploration

    For Each oSubDir In oDir.subfolders                 ' boucle sur les dossiers
          
            If Err.Number = 0 Then
            FSO_List_FICHIERS2 oSubDir, PartName        ' on relance la fonction ( appel récursif)
        Else: Err.Clear                                 ' sinon on clear l'erreur si dossier interdit ou special
        End If
    Next oSubDir

    On Error GoTo 0                                     ' ferme la gestion d'erreur globale

' si c'est le premier appel  donc on a lu tout l'arborescence en appels récursifs on peut maintenant instruire le return de la fonction avec le tableau
    If First_Call Then
        FSO_List_FICHIERS2 = False                      ' on met le return de la fonction a false
        If NbFichiers > 0 Then FSO_List_FICHIERS2 = tbl ' si NbFichiers est plus grand que 0 le return de la fonction est la tableau
    End If

End Function

et pour l'utiliser

dans le module ou un autre module tu met par exemple
on va rechercher tout les fichiers portant dans le nom la chaine "toto"

si tu cherche des fichiers excel par exemple xlsx ou xlsm ou xltm etc et portant dans le nom la chaine"taratata"
et bien c'est Const Ext$ = "*tartata.xl*"
ca va donc te trouver tout les fichier sous toute les format d'excel

Code:
Sub listeFSOGOSUB()
    Dim Table As Variant, tim
    ActiveSheet.Range("A1:A" & Rows.Count).ClearContents
    Const Répertoire = thisworkbook.path
    tim = Timer
    Const Ext$ = "*toto.*"
      Table = FSO_List_FICHIERS2(Répertoire, Ext)
    If IsArray(Table) Then
        Table = TransposeArray(Table)
        tim = Format(Timer - tim, "#0.000 S")

        MsgBox UBound(Table) & " fichier(s) <""" & Ext & """> trouvé(s) dans le répertoire <" & Répertoire & "> en " & tim & " s/"
        
        ActiveSheet.Range("A1").Resize(UBound(Table)).Value = Table

    Else
        MsgBox "Aucun fichier dans le répertoire <" & Répertoire & ">" & vbCrLf & "ayant une partie du nom contenant  " & Ext
    End If
End Sub
voilà on se retrouve avec une fonction quasiment aussi rapide que DIR
 

TaigaLupus

XLDnaute Nouveau
Waouuu t'es un grand malade (dans le bon sens du terme evidemment) en tous cas tu es mon gourou du VBA et chaque soir j'allumerais un cierge en ton nom !!! bon maintenant il ne me reste plus qu'a tester le code et le comprendre (ouf la il ya du boulot) !!! MERCI, MERCI, MERCI
 

patricktoulon

XLDnaute Barbatruc
re
gourou je sais pas c'est l'expérience c'est tout

c'est @Dudu2 et moi qui avons chercher par tout les moyen à accélérer une fonction récursive avec FSO
et on a decouvert en meme temps les piges justement de la récursivité
nous divergeons un peu pour la destination de partname lui travaille surtout sur l’extension de fichier
le mien partname (ext)sert pour tout il suffit de coder la chaine comme on en a besoins avec les éléments de recherche que l'on souhaite

Const Ext$ = "*toto*blabla*.p*"
recherche tout les fichiers ayant dans le nom quelque chose et "toto" et quelque chose et "blabla" et ayant une extension commençant par "p"
il trouvera des pdf des powerpoint des plx etc.. ayant les chaines demandées dans cet ordre
vous remarquerz que nous avons inclu un dir qui n'est là que pour dire si on tourne ou pas

bref ce fut une longue discussion très enrichissante ( toujours avec @Dudu2)
nous avons passé pal mal d'heures sur ce projet
 

Dranreb

XLDnaute Barbatruc
Bonjour.
Pour faire prendre en compte une expression par une procédure, passez ByVal l'argument correspondant. Ne serait-ce que pour réduire le risque d'une erreur de compilation "Type d'argument ByRef incompatible", mais aussi pour d'autres raisons à vocation documentaire, logique et technique. C'est mieux à tout point de vue.
 

Discussions similaires

Les cookies sont requis pour utiliser ce site. Vous devez les accepter pour continuer à utiliser le site. En savoir plus…