Lister tous les sous répertoires et les fichiers

Magentha Messages postés 28 Date d'inscription jeudi 1 septembre 2005 Statut Membre Dernière intervention 14 avril 2022 - 11 avril 2022 à 14:17
 Whismeril - 14 avril 2022 à 13:32
Bonjour à tous.
j'utilise le code (vb.net) ci-dessous pour afficher dans un listbox tous les sous répertoires et les fichiers d'un répertoire. Mais s'il existe un sous répertoire vide, celui-ci sera ignoré et ne sera pas affiché. Pouvez vous m'aider a résoudre ce problème.

Try
Directory.GetFiles(sourceRep, "*.*", SearchOption.AllDirectories)

Dim repficTrouv = Directory.GetFiles(sourceRep, "*.*", SearchOption.AllDirectories)

For Each ligneF In repficTrouv

ListBox1.Items.Add(ligneF)

Next
Catch ex As Exception
TextBox1.Text = ex.Message
End Try

D'avance merci pour vos conseils et votre aide.

6 réponses

Whismeril Messages postés 19011 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 10 avril 2024 654
Modifié le 12 avril 2022 à 22:14
Bonsoir
dans ton code actuel la ligne 2 ne sert à rien, enfin si à perdre du temps d'exécution et de charger inutilement la RAM.
Dans la ligne 3 tu lances une deuxième fois la méthode GetFiles, mais cette fois tu stockes le résultat.
Donc 2 fois le travail de listing de tous les fichiers dans tous les sous dossiers.
La méthode GetFiles est récursive ce qui explique que son appel charge la RAM, et selon le nombre de fichiers et de sous dossiers un appel peut être (très) long, donc 2 appels encore plus. Et vu qu'on a déjà chargé la RAM, probablement plus que 2 fois plus.

Donc le code ci-dessus me permet d'afficher tous les dossiers et sous dossiers d'un disque ou d'un dossier, a condition qu'il ne soient pas vides car dans ce cas ils sont ignorés.

En fait non, ce code ne te retourne que les chemins complets des fichiers.
Comme les chemins complets contiennent les noms de tous les dossiers de l'arborescence, tu vois ces dossiers dans ta listbox, mais jamais il ne t'affiche que le chemin du répertoire qui contient le fichier, à l'instar de l'explorateur windows. Et donc, dans les dossiers où il n'y a pas de fichiers, il n'y a aucun affichage.

Ce que tu dois faire c'est écrire une méthode récursive qui combine GetFiles et GetDirectory, sans l'option AllDirectories et que tu gère toi même la "descente" dans chaque dossier.

Attention, si tu utilises ces 2 méthodes sur un dossier système, tu auras une erreur de droit d'accès, même en session administrateur.

1
vb95 Messages postés 3469 Date d'inscription samedi 11 janvier 2014 Statut Contributeur Dernière intervention 8 avril 2024 169
11 avril 2022 à 17:30
Bonjour
Pour poster du code prière de suivre ce tuto : https://codes-sources.commentcamarche.net/faq/11288-les-balises-de-code .
Votre code sera bien plus agréable à lire .
De plus pour votre projet vérifiez que Option Strict et Option Explicit soient toutes les deux sur True ( voir les propriétés du projet --> Onglet Application ) .


Ensuite on verra ce qu'il faut faire .
0
Magentha Messages postés 28 Date d'inscription jeudi 1 septembre 2005 Statut Membre Dernière intervention 14 avril 2022 1
12 avril 2022 à 21:41
Désolé pour la présentation non idoine précédente de mon bout de code et merci pour le Tuto qui m'a permis de la rectifier comme ci-dessous.

Try
    Directory.GetFiles(sourceRep, "*.*", SearchOption.AllDirectories)
    Dim repficTrouv = Directory.GetFiles(sourceRep, "*.*", SearchOption.AllDirectories)
    For Each ligneF In repficTrouv
        ListBox1.Items.Add(ligneF)
    Next
Catch ex As Exception
    TextBox1.Text = ex.Message
End Try


Et en ce qui concerne " Option Strict et Option Explicit" de mon projet, elles sont toutes les deux sur "True".
Donc le code ci-dessus me permet d'afficher tous les dossiers et sous dossiers d'un disque ou d'un dossier, a condition qu'il ne soient pas vides car dans ce cas ils sont ignorés. Comment faire pour que tous les dossiers vides ou non soient listés.
Encore merci pour votre aide.
0
Magentha Messages postés 28 Date d'inscription jeudi 1 septembre 2005 Statut Membre Dernière intervention 14 avril 2022 1
14 avril 2022 à 00:16
Merci voici le code qui grâce à vos conseils me permet de lister tous les sous répertoires même vides ainsi que tous les fichiers d'un répertoire racine. Cela fonctionne également a partir de la racine d'un disque mais beaucoup moins bien (nombre d'éléments et traitement des erreurs) car ce code est loin d’être optimisé.
Pour tester le code j'ai utiliser :
- Un Form
- Une listbox
- Un Bouton
- Un Label
Je vais essayer de continuer à gratter pour l' améliorer.

Imports System.IO
Public Class Form1
    Dim DirSubDirArray As New ArrayList
    Dim sourceDir As String = "D:\Gestion"

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim DirArray As New ArrayList

        GetAllDir(sourceDir, DirArray)
        DirArray.Clear()

        For Each item In DirSubDirArray
            Try
                If Directory.GetFiles(item, "*.*", SearchOption.TopDirectoryOnly).Length > 0 Then
                    getFichiers(item)
                Else
                    ListBox2.Items.Add(item & "\")
                End If
            Catch er As Exception           'gérer les refus pour les fichiers d'accès  protégés
                Label1.Text = er.Message
            End Try
        Next
        DirSubDirArray.Clear()
    End Sub

     'Obtenir tous les dossiers et les sous dossier
    Sub GetAllDir(ByVal StartPath As String, ByRef directoryList As ArrayList)
        Try
            Dim subDirs() As String = Directory.GetDirectories(StartPath)

            For Each Dir As String In subDirs
                GetAllDir(Dir, directoryList)       'appel récurcif pour obtenir tous les sous répertoires
                DirSubDirArray.Add(Dir)            'mémorise tous les sous répertoires
            Next
        Catch er As Exception           'gérer les refus pour les fichiers d'accès protégés
            Label1.Text = er.Message
        End Try
    End Sub

    'Obtenir tous les fichiers de chaque sous dossier
    Sub getFichiers(dossier As String)
        Dim fichiers = Directory.GetFiles(dossier, "*.*", SearchOption.TopDirectoryOnly)
        For Each fic In fichiers
            ListBox2.Items.Add(fic)
        Next
    End Sub

End Class
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Whismeril Messages postés 19011 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 10 avril 2024 654
14 avril 2022 à 11:22
Bonjour

Oui déjà dans l’idée il ne devrais pas y avoir de « recherche » dans la méthode abonnée au click du bouton, tout devrait se faire dans la méthode récursive.

Ensuite, ligne 9 tu appelles getalldir, qui rempli l’arraylist (perso je préfère une List(of String) mais bon), et à la ligne 10 du vide cette arraylist, ça n’a pas de sens.

De plus, en l’état ton code n’est pas réutilisable, si tu le copies colles dans un autre projet, il va chercher label1 et listbox2, or dans ce nouveau projet il y a textbox3 et listview4…
Ce qu’il faudrait c’est que la méthode récursive soit une fonction qui retourne la liste des fichiers / dossiers et la liste des messages d’erreur (par ce qu’en plus là au final tu ne verras que le dernier s’il y a en plusieurs)

Et enfin, le temps que ça pédale, ton ihm va être figée, faire tout ça dans un thread séparé serait une bonne chose.
0
un exemple vite fait, avec 2 listbox, un bouton et un backgroundworker

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
        backgroundWorker1.DoWork += AddressOf BackgroundWorker1_DoWork 'thread principal du backgroundworker
        backgroundWorker1.WorkerReportsProgress = True 'autorise le thread principale à envoyer une progression
        backgroundWorker1.ProgressChanged += AddressOf BackgroundWorker1_ProgressChanged 'abonnement à l'évènement de progression
        backgroundWorker1.RunWorkerCompleted += AddressOf BackgroundWorker1_RunWorkerCompleted ' abondment à l'évènement signalant la fin du trhead principal
    End Sub

    ''' <summary>
    ''' Méthode qui est lancée quand on active le travail du backgroundworker, elle en constitue le thread principal
    ''' </summary>
    ''' <paramname="sender"></param>
    ''' <paramname="e"></param>
    Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
        Dim resultat As List(Of String) = New List(Of String)()
        Dim erreurs As List(Of String) = New List(Of String)()
        Explorer(e.Argument.ToString(), resultat, erreurs)
        e.Result = New Object(){resultat, erreurs}
    End Sub


    ''' <summary>
    ''' Méthode récursive d'exploration de fichiers / dossiers
    ''' </summary>
    ''' <paramname="CheminRacine"></param>
    ''' <paramname="Resultat"></param>
    ''' <paramname="Erreurs"></param>
    Private Sub Explorer(ByVal CheminRacine As String, ByVal Resultat As List(Of String), ByVal Erreurs As List(Of String))
        backgroundWorker1.ReportProgress(0) 'on envoie n'importe quoi comme progression car on ne connait pas le nombre de regression, mais on annime le curseur à chaque étape

        Try
            Resultat.AddRange(Directory.GetFiles(CheminRacine))

            For Each d In Directory.GetDirectories(CheminRacine)
                Resultat.Add(d & "\")
                Explorer(d, Resultat, Erreurs)
            Next

        Catch e As Exception
            Erreurs.Add(e.Message)
        End Try
    End Sub


    ''' <summary>
    ''' Méthode permettant d'afficher une progression, en général une barre qui avance
    ''' </summary>
    ''' <paramname="sender"></param>
    ''' <paramname="e"></param>
    Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)
        'force le curseur à afficher le symbole d'attente (une "roue" qui tourne sous W10)
        If Cursor.Current IsNot Cursors.WaitCursor Then Cursor.Current = Cursors.WaitCursor
    End Sub


    ''' <summary>
    ''' Méthode qui est lancée quand le travail du backgroundwork est fini
    ''' </summary>
    ''' <paramname="sender"></param>
    ''' <paramname="e"></param>
    Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
        Dim res = CType(e.Result, Object())
        listBox1.DataSource = CType(res(0), List(Of String)).Take(100).ToList() 'dans mon test sur c:\windows, j'ai 281 419 c'est trop long à afficher donc je ne mets que les 100 premiers
        listBox2.DataSource = CType(res(1), List(Of String)) ' dans mon test j'ai 30 erreurs d'accès.
        Cursor.Current = Cursors.[Default]
    End Sub

    Private Sub button1_Click(ByVal sender As Object, ByVal e As EventArgs)
        If backgroundWorker1.IsBusy Then
            MessageBox.Show("Il y a déja une recherche en cours")
            Return
        End If

        backgroundWorker1.RunWorkerAsync("C:\Windows")
    End Sub
0
Rejoignez-nous