Recherche recursive

Résolu
Rapakooti Messages postés 90 Date d'inscription mercredi 4 décembre 2002 Statut Membre Dernière intervention 18 mai 2018 - 9 nov. 2012 à 13:42
Rapakooti Messages postés 90 Date d'inscription mercredi 4 décembre 2002 Statut Membre Dernière intervention 18 mai 2018 - 8 déc. 2012 à 18:22
Bonjour,
je me tourne de nouveau vous, car je rencontre une difficulté.
Je suis en train de developpé un programme qui dans ces fonctions scanné un repertoire que je lui indique pour voir si il y a des fichiers AVI ou MKV, (je vous cache pas que c'est pour gerer mes films de vacances...)

Avant j'indiquais un programme un repertoire, via un bouton ou autre, et cela lancais une procedure, maitenant je veux stocker plusieurs repertoire, des les scanner si besoins ( pour verifier si par exemple de nouveau films sont présent)
VOila mon probleme; j'ai essayé d'intégré cette fonction dans une boucle , mais cela ne fonctionne pas car la procedure peut etre longue car repertoire consequent.

J'ai deja essaye de mettre cette procedure dans des thread, mais cela me provoque une grosse erreur car dans cette procdure il y a creation de thread pour evité que ca fasse figer le programme.... merci d'avoir tenu jusque la lol
Je vois par comment faire a par a la limite via backgrounder mais je n'arrive pas a les utilisé, et je galere avec

Avez vous une idée, ou une ame charitable est elle prete a m'aider.

Voici la procedure en question je l'appel quand j'ai besoin





        #region function ajout repertoire
        //Procedure d'ajout de film via une recherche recursive
        private void Ajoutrep(bool ajout)
        {
            if (ajout == true)
            {
                //Creation folderbrowser
                FolderBrowserDialog folderDlg = new FolderBrowserDialog();

                folderDlg.ShowNewFolderButton = true;

                // Montre le FolderBrowserDialog.

                DialogResult result = folderDlg.ShowDialog();
                // Si le bouton selectionnez est ok >
                if (result == DialogResult.OK)
                {
                    if (folderDlg.SelectedPath != "")
                    {
                        Trepertoire.Text = folderDlg.SelectedPath;
                        progressBar1.Visible = true;
                        progressBar1.Style = ProgressBarStyle.Marquee;
                        Environment.SpecialFolder root = folderDlg.RootFolder;
                        // MessageBox.Show("Attention pendant la recherche la fenetre active du programme peut figer", "Attention", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        //lance la recherche recursive


                        // BPH : vaut-il mieux parcourir l'ensemble des fichiers une fois et tester l'extension
                        // ou parcourir autant de fois les répertoires que d'extensions a traiter ?
                        // a determiner par des tests mais je dirais plutot la première option 
                        // (dependante uniquement du nombre de fichiers dans les repertoires qq soit le nb d'extensions a traiter)


                        // on recupere la liste courante pour ne pas ajouter de doublon
                        var currentList new HashSet<string>(dataGridView1.Rows.OfType<DataGridViewRow>().Select(r> (string)r.Cells[1].Value));

                        // on declare ici une tache de fond qui fera le recherche en parallele du "thread UI", evitant ainsi de figer l'interface
                        // qui peut continuer de recevoir et traiter les evenements de la fenetre.
                        var task new Task(()>
                        {
                            // On utilisera EnumerateFiles qui renvoie les fichiers un a un alors que GetFiles va tous les rechercher d'abord et les renvoyer en une fois dans un tableau
                            // Avec GetFiles, on ne pourrait pas avoir la liste qui se remplit au fur et a mesure dans la grille
                            // mathingFiles est ce qu'on appelle une requete Linq, je te laisse decouvrir ca sur le net, cela evite notamment beaucoup de boucles foreach !
                            // BONUS : j'ai remplacé Directory.EnumerateFiles par une methode perso qui ne plante pas qd elle tombe sur un fichier ou repertoire inaccessible ;-)
                            var matchingFiles = EnumerateAccessableFiles(Trepertoire.Text, "*", SearchOption.AllDirectories)
                                .Where(filePath => extensions.Contains(Path.GetExtension(filePath).ToLower())) // ... uniquement les extensions souhaitées
                                .Where(filePath => excludedKeywords.Any(kw => filePath.Contains(kw)) == false) // ... sans les mots clés exclus
                                .Where(filePath => currentList.Contains(filePath) == false) // ... et sans doublon
                                .Select(filePath => new // classes anonyme locale au scope de matchingFiles uniquement
                                {
                                    HasNFO = File.Exists(Path.GetDirectoryName(filePath) + "/" + Path.GetFileNameWithoutExtension(filePath) + ".nfo"),
                                    FilePath = filePath
                                });

                            // le pb avec les controles graphiques est qu'il ne peuvent pas etre modifiés en dehors de leur thread graphique dédié.
                            // Depuis une tache de fond il faut donc "poster" une fonction qui sera executée dans le contexte du thread UI de la fenetre.
                            // C'est a cela que serve les methodes BeginInvoke des controles.
                            // a noter la syntaxe "() =>...", c'est une declaration de methode anonyme en ligne (une lambda)
                            var count = 0;
                            foreach (var match in matchingFiles)
                            {
                                count++;
                                dataGridView1.BeginInvoke((Action)(() => dataGridView1.Rows.Add(match.HasNFO, match.FilePath, Path.GetFileName(match.FilePath))));
                                toolStripStatusLabel1.Text = "Nombres de films : " + dataGridView1.RowCount.ToString();
                                System.Threading.Thread.Sleep(10);
                            }

                            return count;
                        });

                        // une continuation permet d'executer du code qd la tache se termine (correctement ou en erreur ou les deux au choix)
                        task.ContinueWith((t) =>
                        {


                            toolStripStatusLabel1.Text = "Nombres de films : " + dataGridView1.RowCount.ToString();

                            // D'un point de vue ergonomique, il serait preferable de ne pas trier la liste automatiquement a le fin de la recherche
                            // au risque de perdre la selection et la position courante de l'utilisateur.
                            // Le mieux serait d'avoir une grille capable de trier les lignes en cliquant sur les entetes de colonnes et de laisser faire l'utilisateur

                            //dataGridView1.Sort(dataGridView1.Columns[2], ListSortDirection.Ascending);

                            // attention bug : exception si la liste est vide ;-)
                            // de plus, cf remarque ci dessus, pour ne pas perdre la selection courante de l'utilisateur

                            //dataGridView1.CurrentCell = dataGridView1.Rows[0].Cells[2];

                            // sauvegarde de la liste dans un fichier XML
                            var actualList dataGridView1.Rows.OfType<DataGridViewRow>().Select(r> new { HasNFO = (bool)r.Cells[0].Value, FilePath = (string)r.Cells[1].Value });
                            var xDoc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
                                new XElement("VideoList",
                                    actualList.Select(l => new XElement("FilePath", l.FilePath, new XAttribute("HasNFO", l.HasNFO)))));
                            xDoc.Save(xmlListFilePath);
                            progressBar1.Visible = false;
                            progressBar1.Style = ProgressBarStyle.Continuous;
                            if (t.Result != 0)
                            {
                                MessageBox.Show(String.Format("{0} nouveaux fichiers trouvés", t.Result), "Recherche terminée.", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            }
                            if (t.Result == 0)
                            {
                                MessageBox.Show(String.Format("Pas de nouveau fichier trouvé"), "Recherche terminée.", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            }
                        },
                        TaskScheduler.FromCurrentSynchronizationContext());

                        // ici on demarre rellement l'exécution de la tache !
                        task.Start();

                    }
                }
            }

        }
        #endregion

R A P A K O O T I

30 réponses

Rapakooti Messages postés 90 Date d'inscription mercredi 4 décembre 2002 Statut Membre Dernière intervention 18 mai 2018
8 déc. 2012 à 18:22
Merci a tous pour votre aide et vos reponse j'ai pu resoudre mon probleme avec un timer et une incrementation

R A P A K O O T I
3
BarthOlivier Messages postés 132 Date d'inscription mercredi 6 mars 2002 Statut Membre Dernière intervention 27 novembre 2012 1
9 nov. 2012 à 16:32
Peut-etre moche (utilisation de doevents() .. j'arrive pas a m'en passer depuis tout ce temps)

Par contre je suis encore en 2.0 .. donc surement améliorable avec le //



        public IEnumerable<string> ControlsAvecRecursivite(string strPath)
        {
            DirectoryInfo dInfo = new DirectoryInfo(strPath);
            System.Security.AccessControl.DirectorySecurity secu = dInfo.GetAccessControl();
            bool protect1 = secu.AreAuditRulesProtected;
            bool protect2 = secu.AreAccessRulesProtected;

            if (!protect1 && !protect2)
            {
                foreach (string c in Directory.EnumerateFiles(strPath, "*"))
                {
                    if(testTypeFileIsGood(c))
                    {
                    listBox1.Items.Add(c);
                    toolStripStatusLabel1.Text = (Count++).ToString() + "Fichiers trouvés";
                    Application.DoEvents();
                    yield return c;
                    }
                }

                foreach (string c in Directory.EnumerateDirectories(strPath, "*"))
                    foreach (string child in ControlsAvecRecursivite(c))
                    {
                        yield return child;
                    }
            }
        }


La fonction <testTypeFileIsGood> te sert a filtrer ce que tu veux exactement.
Code perfectible ... juste fait en peu de temps

Si ca te conviens ou t'aiguille sur une piste plus fonctionnelle

MisterMok
0
Rapakooti Messages postés 90 Date d'inscription mercredi 4 décembre 2002 Statut Membre Dernière intervention 18 mai 2018
9 nov. 2012 à 16:48
J'utilise aussi ce code afin d'évité les erreurs

 // version "ameliorée" de EnumerateFiles qui ignore les exceptions sur les fichiers/répertoires inaccessibles
        // et passe aux suivants sans s'arreter !
        private static IEnumerable<String> EnumerateAccessableFiles(string path, string file_pattern, SearchOption searchOption)
        {
            // Enumerate the files just in the top directory.
            var files = Directory.EnumerateFiles(path, file_pattern).GetEnumerator();

            while (true)
            {
                String file = null;
                try
                {
                    if (files.MoveNext())
                        file = files.Current;
                    else
                        break;
                }
                catch (UnauthorizedAccessException)
                {
                    continue;
                }
                catch (PathTooLongException)
                {
                    continue;
                }

                yield return file;
            }

            if (searchOption == SearchOption.TopDirectoryOnly)
                yield break;

            var dirs = Directory.EnumerateDirectories(path, "*").GetEnumerator();

            while (true)
            {
                String dir = null;
                try
                {
                    if (dirs.MoveNext())
                        dir = dirs.Current;
                    else
                        break;
                }
                catch (UnauthorizedAccessException)
                {
                    continue;
                }
                catch (PathTooLongException)
                {
                    continue;
                }

                foreach (var subpath in EnumerateAccessableFiles(dir, file_pattern, searchOption))
                    yield return subpath;
            }
        }




En fait la fonction en elle meme me satisfait, ma datagried se remplit au fur et a mesure donc nickel , pas d'erreur , mais avant j'utilisais un textbox, et maintenant je voudrais avoir juste une boucle qui change la variable. j'ai une liste qui contient 3 emplacement ou plus et je fais un foreach dessus.Apres je peux changer pour autre chose qu'une boucle lol


R A P A K O O T I
0
BarthOlivier Messages postés 132 Date d'inscription mercredi 6 mars 2002 Statut Membre Dernière intervention 27 novembre 2012 1
9 nov. 2012 à 17:58
J'ai pas compris alors ce que tu cherchais a faire ... le problème dans la thread viens d'où exactement (vu que tu as essayé) ?

Peut-tu preciser ce que tu veux faire avec la threads (entrées / sorties) ?

MisterMok
0

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

Posez votre question
Rapakooti Messages postés 90 Date d'inscription mercredi 4 décembre 2002 Statut Membre Dernière intervention 18 mai 2018
9 nov. 2012 à 18:02
Bonjour,
En fait je voudrais pouvoir le faire plusieurs fois pour le mettre dans une boucle, j'ai essayé mais cela ne marche pas car la procedure est plus longue que la boucle :-)
et impossible de le mettre dans un thread que la procedure en contient un

R A P A K O O T I
0
BarthOlivier Messages postés 132 Date d'inscription mercredi 6 mars 2002 Statut Membre Dernière intervention 27 novembre 2012 1
9 nov. 2012 à 19:01
Tu as essayé ( oui toujours mon 2.0) de passer par des délégué avec ta thread ?

        private delegate void Delegate_ThreadData();
        void ThreadData()
        {
            if (InvokeRequired)
            {
                /*permet de modifier les  controles d'une autre thread sinon plantage d'accès */


                try { Invoke(new Delegate_ThreadData(ThreadData)); } 
                                                                    
                catch { }
            }
            else
            {
                while(m_RUN) // m_run pour sortir de ta boucle autrement qu'en faisant un .ABORT
                  {
System.thread.threading.sleep(200); // <-- pour éviter de prendre trop de temps UC
var matchingFiles = EnumerateAccessableFiles(Trepertoire.Text, "*", SearchOption.AllDirectories)
                                .Where(filePath => extensions.Contains(Path.GetExtension(filePath).ToLower())) // ... uniquement les extensions souhaitées
                                .Where(filePath => excludedKeywords.Any(kw => filePath.Contains(kw)) == false) // ... sans les mots clés exclus
                                .Where(filePath => currentList.Contains(filePath) == false) // ... et sans doublon
                                .Select(filePath => new // classes anonyme locale au scope de matchingFiles uniquement
                                {
                                    HasNFO = File.Exists(Path.GetDirectoryName(filePath) + "/" + Path.GetFileNameWithoutExtension(filePath) + ".nfo"),
                                    FilePath = filePath
                                });

                            // le pb avec les controles graphiques est qu'il ne peuvent pas etre modifiés en dehors de leur thread graphique dédié.
                            // Depuis une tache de fond il faut donc "poster" une fonction qui sera executée dans le contexte du thread UI de la fenetre.
                            // C'est a cela que serve les methodes BeginInvoke des controles.
                            // a noter la syntaxe "() =>...", c'est une declaration de methode anonyme en ligne (une lambda)
                            var count = 0;
                            foreach (var match in matchingFiles)
                            {
                                count++;
                                dataGridView1.BeginInvoke((Action)(() => dataGridView1.Rows.Add(match.HasNFO, match.FilePath, Path.GetFileName(match.FilePath))));
                                toolStripStatusLabel1.Text = "Nombres de films : " + dataGridView1.RowCount.ToString();
                                System.Threading.Thread.Sleep(10);
                            }
}
}
            }
#endif
        }

(Attention copié/coller de ton code avec quelques modif, surement des erreur a la compilation)
Dans l'idée tu lances ta thread qui tourne en boucle de façon séquentielle et tu peux travailler
a partir du tableau .. (si j'ai bien compris ce que tu voulais, RTT oblige -> cerveau en mode idle).


MisterMok
0
Rapakooti Messages postés 90 Date d'inscription mercredi 4 décembre 2002 Statut Membre Dernière intervention 18 mai 2018
10 nov. 2012 à 23:10
je dis pas non mais je crois que la cela me depasse lol, j'avoue que une grande partie de ce code n'etait pas de moi :-) je pensais qu'il y avait un truc simple :-)


R A P A K O O T I
0
Rapakooti Messages postés 90 Date d'inscription mercredi 4 décembre 2002 Statut Membre Dernière intervention 18 mai 2018
11 nov. 2012 à 00:35
j'ai integre la boucle dans le thread , j'ai plus d'erreur mais le pc ne trouve rien

 #region function ajout repertoire
        //Procedure d'ajout de film via une recherche recursive
        private void Ajoutrep(bool ajout)
        {
            if (ajout == true)
            {
                //Creation folderbrowser
                   string listedossiersep = Properties.Settings.Default.listedossier;
            string []  dossierascanne = listedossiersep.Split('*');
            foreach (string dossierscanner in dossierascanne)
            {
                        progressBar1.Visible = true;
                        progressBar1.Style = ProgressBarStyle.Marquee;
                    //    Environment.SpecialFolder root = folderDlg.RootFolder;
                        // MessageBox.Show("Attention pendant la recherche la fenetre active du programme peut figer", "Attention", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        //lance la recherche recursive


                        // BPH : vaut-il mieux parcourir l'ensemble des fichiers une fois et tester l'extension
                        // ou parcourir autant de fois les répertoires que d'extensions a traiter ?
                        // a determiner par des tests mais je dirais plutot la première option 
                        // (dependante uniquement du nombre de fichiers dans les repertoires qq soit le nb d'extensions a traiter)

                        MessageBox.Show(dossierscanner);
                        // on recupere la liste courante pour ne pas ajouter de doublon
                        var currentList new HashSet<string>(dataGridView1.Rows.OfType<DataGridViewRow>().Select(r> (string)r.Cells[1].Value));

                        // on declare ici une tache de fond qui fera le recherche en parallele du "thread UI", evitant ainsi de figer l'interface
                        // qui peut continuer de recevoir et traiter les evenements de la fenetre.
                        var task new Task(()>
                        {
                            // On utilisera EnumerateFiles qui renvoie les fichiers un a un alors que GetFiles va tous les rechercher d'abord et les renvoyer en une fois dans un tableau
                            // Avec GetFiles, on ne pourrait pas avoir la liste qui se remplit au fur et a mesure dans la grille
                            // mathingFiles est ce qu'on appelle une requete Linq, je te laisse decouvrir ca sur le net, cela evite notamment beaucoup de boucles foreach !
                            // BONUS : j'ai remplacé Directory.EnumerateFiles par une methode perso qui ne plante pas qd elle tombe sur un fichier ou repertoire inaccessible ;-)
                            var matchingFiles = EnumerateAccessableFiles(dossierscanner, "*", SearchOption.AllDirectories)
                                .Where(filePath => extensions.Contains(Path.GetExtension(filePath).ToLower())) // ... uniquement les extensions souhaitées
                                .Where(filePath => excludedKeywords.Any(kw => filePath.Contains(kw)) == false) // ... sans les mots clés exclus
                                .Where(filePath => currentList.Contains(filePath) == false) // ... et sans doublon
                                .Select(filePath => new // classes anonyme locale au scope de matchingFiles uniquement
                                {
                                    HasNFO = File.Exists(Path.GetDirectoryName(filePath) + "/" + Path.GetFileNameWithoutExtension(filePath) + ".nfo"),
                                    FilePath = filePath
                                });

                            // le pb avec les controles graphiques est qu'il ne peuvent pas etre modifiés en dehors de leur thread graphique dédié.
                            // Depuis une tache de fond il faut donc "poster" une fonction qui sera executée dans le contexte du thread UI de la fenetre.
                            // C'est a cela que serve les methodes BeginInvoke des controles.
                            // a noter la syntaxe "() =>...", c'est une declaration de methode anonyme en ligne (une lambda)
                            var count = 0;
                            foreach (var match in matchingFiles)
                            {
                                count++;
                                dataGridView1.BeginInvoke((Action)(() => dataGridView1.Rows.Add(match.HasNFO, match.FilePath, Path.GetFileName(match.FilePath))));
                                //toolStripStatusLabel1.Text = "Nombres de films : " + dataGridView1.RowCount.ToString();
                                System.Threading.Thread.Sleep(100);
                            }
                            
                            return count;
                        });

                        // une continuation permet d'executer du code qd la tache se termine (correctement ou en erreur ou les deux au choix)
                        task.ContinueWith((t) =>
                        {


                            toolStripStatusLabel1.Text = "Nombres de films : " + dataGridView1.RowCount.ToString();

                            // D'un point de vue ergonomique, il serait preferable de ne pas trier la liste automatiquement a le fin de la recherche
                            // au risque de perdre la selection et la position courante de l'utilisateur.
                            // Le mieux serait d'avoir une grille capable de trier les lignes en cliquant sur les entetes de colonnes et de laisser faire l'utilisateur

                            //dataGridView1.Sort(dataGridView1.Columns[2], ListSortDirection.Ascending);

                            // attention bug : exception si la liste est vide ;-)
                            // de plus, cf remarque ci dessus, pour ne pas perdre la selection courante de l'utilisateur

                            //dataGridView1.CurrentCell = dataGridView1.Rows[0].Cells[2];

                            // sauvegarde de la liste dans un fichier XML
                            var actualList dataGridView1.Rows.OfType<DataGridViewRow>().Select(r> new { HasNFO = (bool)r.Cells[0].Value, FilePath = (string)r.Cells[1].Value });
                            var xDoc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
                                new XElement("VideoList",
                                    actualList.Select(l => new XElement("FilePath", l.FilePath, new XAttribute("HasNFO", l.HasNFO)))));
                            xDoc.Save(xmlListFilePath);
                            progressBar1.Visible = false;
                            progressBar1.Style = ProgressBarStyle.Continuous;
                            if (t.Result != 0)
                            {
                              //  MessageBox.Show(String.Format("{0} nouveaux fichiers trouvés", t.Result), "Recherche terminée.", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            }
                            if (t.Result == 0)
                            {
                              //  MessageBox.Show(String.Format("Pas de nouveau fichier trouvé"), "Recherche terminée.", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            }
                        },
                        TaskScheduler.FromCurrentSynchronizationContext());

                        // ici on demarre rellement l'exécution de la tache !
                        task.Start();

                    }
            }



R A P A K O O T I
0
BarthOlivier Messages postés 132 Date d'inscription mercredi 6 mars 2002 Statut Membre Dernière intervention 27 novembre 2012 1
11 nov. 2012 à 10:46
bon, voici un truc que je viens de faire a l'arrache qui semble fonctionner.

je ne filtre que les fichiers ".txt", et je n'ai pas géré l'archivage pour gérer
les nouveaux fichiers. Mais faut bien te laisser un peu d'amusement sinon c'est
plus rigolo.

        int Count = 0;
        int CountAll = 0;
        bool m_RUN = false;

        System.Threading.Thread MyThread;
        //---------------------------------------------------------------------------//
        private delegate void Delegate_ThreadData();
        void ThreadData()
        {
            if (InvokeRequired)
            {
                /*permet de modifier les  controles d'une autre thread sinon plantage d'accès */


                try { Invoke(new Delegate_ThreadData(ThreadData)); }

                catch { }
            }
            else
            {
                while (m_RUN) // m_run pour sortir de ta boucle autrement qu'en faisant un .ABORT
                {
                    Count = 0;
                    CountAll = 0;
                    foreach (string strFichier in ChercheFiles("F:\"))
                    {
                        listBox1.Items.Add(strFichier);
                        toolStripStatusLabel1.Text = (Count).ToString() + "Fichiers trouvés";
                        toolStripStatusLabel2.Text = "sur " + (CountAll).ToString() + " Fichiers au total";
                    }
                    System.Threading.Thread.Sleep(1000);
                }
            }
        }
        //---------------------------------------------------------------------------//
        bool testTypeFileIsGood(string file)
        {
            if(Path.GetExtension(file) == ".txt")
                return true;
            else
                return false;
        }
        //---------------------------------------------------------------------------//
        public IEnumerable ChercheFiles(string strPath)
        {
            DirectoryInfo dInfo = new DirectoryInfo(strPath);
            System.Security.AccessControl.DirectorySecurity secu = dInfo.GetAccessControl();
            bool protect1 = secu.AreAuditRulesProtected;
            bool protect2 = secu.AreAccessRulesProtected;

            if (!protect1 && !protect2)
            {
                foreach (string c in Directory.EnumerateFiles(strPath, "*"))
                {
                    CountAll++;
                    if (testTypeFileIsGood(c))
                    {
                        Count++;
                        Application.DoEvents();
                        yield return c;
                    }
                }

                foreach (string c in Directory.EnumerateDirectories(strPath, "*"))
                    foreach (string child in ChercheFiles(c))
                    {
                        yield return child;
                    }
            }
        }


        private void button1_Click(object sender, EventArgs e)
        {
// je lance la thread d'ici, après tu fais ce que tu veux.
            m_RUN = true;
            MyThread = new System.Threading.Thread(ThreadData);
            MyThread.Start();
        }


Le résultat s'affiche dans une listbox, après rien ne t’empêche de faire une classe , de mettre
ça dans un tableau de variable, ou tout autre chose pour te faciliter l'exploitation

en espérant que ça te résolve ton problème.

MisterMok
0
Rapakooti Messages postés 90 Date d'inscription mercredi 4 décembre 2002 Statut Membre Dernière intervention 18 mai 2018
11 nov. 2012 à 12:28
Merci c est une piste je suis pas cher moi pour testé , une partie du problème est encore la tu gère un dossier mais je cherche à gérer plusieurs dossier indique par l utilisateur dont certain tes gros qui entraîne une recherche longue et je dois trouve comment attendre la fin de la procédure ou de la tienne avant d en relance une autre fois

R A P A K O O T I
0
BarthOlivier Messages postés 132 Date d'inscription mercredi 6 mars 2002 Statut Membre Dernière intervention 27 novembre 2012 1
11 nov. 2012 à 18:54
Nouvelle proposition ...

Test effectué sur 3 répertoires (3 HDD) contenant au total 116.365 fichiers sur 17188 répertoires
Pc : DualCore 3.16Go et 3Go de RAM
Temps entre 62 et 60s en fonction du mode parallel.foreach ou foreach

Tu passes toujours par une thread optimisée // (? pardon pour les puristes qui trouverons surement plus joli, moins gros
et surement plus rapide)

        int Count = 0;
        int CountAll = 0;
        bool m_RUN = false;

        System.Threading.Thread MyThread;
        List<string> ListPath = new List<string>();
        //---------------------------------------------------------------------------//
        private delegate void Delegate_FuncChercheFichier(string strPath);
        void FuncChercheFichier(string strPath)
        {
            if (InvokeRequired)
            {
                /*permet de modifier les  contrôles d'une autre thread sinon plantage d'accès */
                /* Obligation de le dissocier de la Thread principale à cause du parallélisme Net 4.0 */


                try { Invoke(new Delegate_FuncChercheFichier(FuncChercheFichier), strPath); }

                catch { }
            }
            else
            {
                foreach (string strFichier in ChercheFiles(strPath))
                {
                    listBox1.Items.Add(strFichier);
                    toolStripStatusLabel1.Text = (Count).ToString() + " Fichiers trouvés";
                }

            }
        }

        void ParallelThreadData()
        {
            System.Diagnostics.Stopwatch ST1 = new System.Diagnostics.Stopwatch();
            ST1.Start();

            while (m_RUN) // m_run pour sortir de ta boucle autrement qu'en faisant un .ABORT
            {
                Count = 0;
                CountAll = 0;

                
                Parallel.ForEach(ListPath, Direct =>
                {
                    FuncChercheFichier(Direct);
                });
                
                /*
                foreach(string Direct in ListPath)
                {
                    FuncChercheFichier(Direct);
                }
                */
                System.Threading.Thread.Sleep(1000);
                m_RUN = false; // >> UN SEUL TEST !!
            }
            ST1.Stop();
            MessageBox.Show(ST1.ElapsedMilliseconds.ToString());
            // Se déclenche seulement a la fin de "TOUTE" la procédure donc tu connais la fin.
        }
        
        //---------------------------------------------------------------------------//
        bool testTypeFileIsGood(string file)
        {
            if(Path.GetExtension(file) == ".txt")
                return true;
            else
                return false;
        }
        //---------------------------------------------------------------------------//
        public IEnumerable ChercheFiles(string strPath)
        {
            DirectoryInfo dInfo = new DirectoryInfo(strPath);
            System.Security.AccessControl.DirectorySecurity secu = dInfo.GetAccessControl();
            bool protect1 = secu.AreAuditRulesProtected;
            bool protect2 = secu.AreAccessRulesProtected;

            if (!protect1 && !protect2 && dInfo.Exists /* test complémentaire */ )
            {
                foreach (string c in Directory.EnumerateFiles(strPath, "*"))
                {
                    CountAll++;
                    Application.DoEvents();
                    if (testTypeFileIsGood(c))
                    {
                        Count++;
                        yield return c;
                    }
                }
                foreach (string c in Directory.EnumerateDirectories(strPath, "*"))
                    foreach (string dir in ChercheFiles(c))
                    {
                        yield return dir;
                    }
            }
        }


        private void button1_Click(object sender, EventArgs e)
        {
            m_RUN = true;
            MyThread = new System.Threading.Thread(ParallelThreadData);
            ListPath.Add("D:\");
            ListPath.Add("E:\");
            ListPath.Add("F:\");
            MyThread.Start();
        }


Autre solution (plus rapide et moins bloquante ?) tu crées un autant de thread que de répertoire
et tu remplaces

                Parallel.ForEach(ListPath, Direct =>
                {
                    FuncChercheFichier(Direct);
                });


par

                    FuncChercheFichier(Direct);


Bon tests

MisterMok
0
BarthOlivier Messages postés 132 Date d'inscription mercredi 6 mars 2002 Statut Membre Dernière intervention 27 novembre 2012 1
11 nov. 2012 à 19:22
Apres tu peux virer le comptage lors de la recherche ce qui accelere le temps ( plus d'acces au contrôles
ni gestion des Messages par le doevents)

        public IEnumerable ChercheFiles(string strPath)
        {
            DirectoryInfo dInfo = new DirectoryInfo(strPath);
            System.Security.AccessControl.DirectorySecurity secu = dInfo.GetAccessControl();
            bool protect1 = secu.AreAuditRulesProtected;
            bool protect2 = secu.AreAccessRulesProtected;

            if (!protect1 && !protect2/*&& dInfo.Exists*/)
            {
                foreach (string c in Directory.EnumerateFiles(strPath, "*"))
                {
                    CountAll++;
                    if (testTypeFileIsGood(c))
                    {
                        Count++;
                        yield return c;
                    }
                }
                foreach (string c in Directory.EnumerateDirectories(strPath, "*"))
                    foreach (string child in ChercheFiles(c))
                    {
                        Repertoires++;
                        yield return child;
                    }
            }
        }


et tu passes par la fonction :

        void ParallelThreadData()
        {
            System.Diagnostics.Stopwatch ST1 = new System.Diagnostics.Stopwatch();
            ST1.Start();

            while (m_RUN) // m_run pour sortir de ta boucle autrement qu'en faisant un .ABORT
            {
                Count = 0;
                CountAll = 0;
                Repertoires = 0;
                
                Parallel.ForEach(ListPath, Direct =>
                {
                    FuncChercheFichier(Direct);
                });
                
                
                //System.Threading.Thread.Sleep(1000);
                m_RUN = false; // >> UN SEUL TEST !!
            }
            ST1.Stop();
            MessageBox.Show(ST1.ElapsedMilliseconds.ToString());
        }


Résultats obtenus sur un Dual Core:
Avec un multiprocesseur plus performant tu devrais largement obtenir mieux
pense a virer le stopwatch tu devrais gagner encore un peu. Après en mettant le sleep, tu peux
faire cette boucle autant de fois que tu veux, et l’arrêter par par m_run = false, ou abort pour faire
plus rapide.

18 secondes pour scanner 4 HDD ( dont C: ) avec 33.762 répertoires et 371496 fichiers

Bonne soirée a toi

MisterMok
0
yann_lo_san Messages postés 1137 Date d'inscription lundi 17 novembre 2003 Statut Membre Dernière intervention 23 janvier 2016 26
11 nov. 2012 à 21:18
Salut,

Pour une tâche "arrière plan", le framework a aussi prévu l'objet
BackGroundWorker

avec ses délégués : 
// Le code asynchrone
backgroundWorker1.DoWork += ...
// Fin du process
backgroundWorker1.RunWorkerCompleted += ...
// Progress
backgroundWorker1.ProgressChanged += ...

// Et ses propriétés, comme l'annulation par exemple
DoWorkEventArgs.Cancel


Concernant la recherche récursive, FileSystemInfo fait très bien l'affaire avec une fonction du style :

static void ListDirectoriesAndFiles(FileSystemInfo[] FSInfo, string SearchString)
{
    if (FSInfo == null)
        throw new ArgumentNullException("FSInfo");
    if (SearchString null || SearchString.Length 0)
        throw new ArgumentNullException("SearchString");

    foreach (FileSystemInfo i in FSInfo)
    {
        // is DirectoryInfo, Iterate 
        if (i is DirectoryInfo)
            ListDirectoriesAndFiles(((DirectoryInfo)i).GetFileSystemInfos(SearchString), SearchString);
        // is FileInfo, fait quelque chose avec le fichier
        else if (i is FileInfo)
            DoSomethingWithFile(i);
    }
}


exemple :

string searchStringDir = "*";
FileSystemInfo[] infos = dir.GetFileSystemInfos(searchStringDir);
ListDirectoriesAndFiles(infos, searchStringDir);


bye...
0
Rapakooti Messages postés 90 Date d'inscription mercredi 4 décembre 2002 Statut Membre Dernière intervention 18 mai 2018
12 nov. 2012 à 09:28
Alors deja merci pour ton aide BarthOlivier, j'ai juste encore deux petit souci mais c est vrai que ca fonctionne du tonnere, mais pour les hdd locaux pas pour les lecteurs reseaux et ca c est tres tres genant, de plus faut que j'ajoute une fonction pour filter les films avec une liste de mot banni ( sample , demo,...)

R A P A K O O T I
0
Rapakooti Messages postés 90 Date d'inscription mercredi 4 décembre 2002 Statut Membre Dernière intervention 18 mai 2018
12 nov. 2012 à 21:11
c'est marrant d'ailleur, je fais une recherche sur c: il ne me renvois rien, sur D: il me renvois les fichiers et sur les lecteurs reseaux cela ne fonctionne pas

R A P A K O O T I
0
Rapakooti Messages postés 90 Date d'inscription mercredi 4 décembre 2002 Statut Membre Dernière intervention 18 mai 2018
12 nov. 2012 à 21:48
n'est t il pas possible d'ajouter la possibilite de faire plusieur recherche en meme temps a partir de ma procedure du debut?


R A P A K O O T I
0
BarthOlivier Messages postés 132 Date d'inscription mercredi 6 mars 2002 Statut Membre Dernière intervention 27 novembre 2012 1
13 nov. 2012 à 08:41
Bizarre pour ton "C:\" y'a normalement aucune raison. Peut-être un problème d’accès admin ? et si tu filtres pas tes fichiers tu arrives a lister le contenu de ton HDD ? Ah si .. laisse moi deviner tu bosses sous Windows 7 ...

n'est t il pas possible d'ajouter la possibilité de faire plusieurs recherche en même temps a partir de ma procédure du début?
C'est à dire ? le fait de passer par la parallélisation normalement dispatche le travail sur tous tes processeurs (quand ca fonctionne et si j'ai bien compris). Les processeur travaillent en parallèle : donc finalement en même temps. (je ne maîtrise pas, j'en suis aux balbutiements, j'en suis encore au 2.0)

Pour le réseau j'essayerai d'y jeter un coup d’oeil après le boulot. Regarde sur le net, peut-être quelque chose qui pourrait répondre a ton problème. Et en débuggeant pas à pas, ça fait quoi avec le réseau ? aucun accès du tout ?

MisterMok
0
Rapakooti Messages postés 90 Date d'inscription mercredi 4 décembre 2002 Statut Membre Dernière intervention 18 mai 2018
13 nov. 2012 à 08:50
Pire lol je suis passe sous windows 8 :-)

Non pas d'erreur avec ta procédure pour les lecteur réseau juste qu il ne trouve rien question de droit apparament connu d après les forum :-(
Ta procédure est parfaite ... Mais je me demandais vu que la mienne fonctionnait même si un peu plus lente mais pas de figé donc pas grave ... Comment je pourrais faire pour la relance plusieurs fois sans problème .. J ai essayé les threads mais cela ne fonctionne car elle même en lance un pour évite la figé


R A P A K O O T I
0
BarthOlivier Messages postés 132 Date d'inscription mercredi 6 mars 2002 Statut Membre Dernière intervention 27 novembre 2012 1
13 nov. 2012 à 09:12
Ben en partant de ta procédure, si ca fonctionne bien tu n'as qu'a faire une boucle infinie

while(m_run)
{
Ajoutrep(bool ajout);
}


avec un DoEvents() à chaque boucle sensible. ce qui t’évite de figer ton appli

Et si tu as un probleme d'acces aux controles dans ta Task() ce qui est possible tu passes
par un délegué

private delegate void Delegate_FuncChercheFichier(var strPath);
        void FuncChercheFichier(var strPath)
        {
            if (InvokeRequired)
            {
                try { Invoke(new Delegate_FuncChercheFichier(FuncChercheFichier), strPath); }
                catch { }
            }
            else
            {
// ACCES A TES CONTROLS
            }


MisterMok
0
Rapakooti Messages postés 90 Date d'inscription mercredi 4 décembre 2002 Statut Membre Dernière intervention 18 mai 2018
13 nov. 2012 à 09:33
Merci je vais voir alors pour mettre ma procédure ou plutot sont lancement dans une boucle infini :-)
R A P A K O O T I
0
Rejoignez-nous