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
17 nov. 2012 à 18:07
bonsoir,
vous feriez comment vous? j'ai bien essaye mais meme en adaptant les deux procedure ca donne rien
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
18 nov. 2012 à 10:37
On peux avoir l'ensemble de ton projet ? (du moins un truc compilable avec cette fonction qui te gène tant)

MisterMok
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
18 nov. 2012 à 11:13
Bonjour, Linq ( à partir de la framework 3) permet de manipuler les dossier de la même façon (ou à peu près) que des données xml, sql etc...

J'avais un exemple quelque par mais je ne le trouve plus.

Par contre sur le forum, il y a un tuto ou c'est abordé, dans la section linq to object


Whismeril
0
Rapakooti Messages postés 90 Date d'inscription mercredi 4 décembre 2002 Statut Membre Dernière intervention 18 mai 2018
18 nov. 2012 à 11:26
Oui cela me gêne pas mais j ai déjà tous poste en fait pour l instant j appelle la fonction mit dans mon premier post Ajoutrep(true) avec un empalement dans un textedit. Le passé de paramètre en lui même est pas un souci .

Mais voilà maintenant j ai une listbox avec autant de répertoire que la personne souhaite . Et c est la que le souci commence Ajoutrep ne fonctionne pas dans la boucle foreach de la list car cela lance une nouvelle procédure alors que l ancienne est pas termine .

R A P A K O O T I
0

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

Posez votre question
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
18 nov. 2012 à 11:32
J'ai remanié l'exemple du tuto vite fait, pour trouver 1 word et deux xml rangés dans mon dossier d'exécution, le tout retourné dans une liste de string

            string temp = Application.StartupPath;

            DirectoryInfo info = new DirectoryInfo(temp);

            List<string> query = (from f in info.GetFiles()

                        where f.Extension ".doc" | f.Extension ".xml" 

                        orderby f.Length descending

                        select f.Name).ToList<string>() ;



Whismeril
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
18 nov. 2012 à 11:40
et voila pour regarder dans 2 répertoires

            DirectoryInfo[] infos = new DirectoryInfo[2];
            infos[0] = new DirectoryInfo(Application.StartupPath);
            infos[1] = new DirectoryInfo(@"c:\temp");


            List<string> query = (from info in infos
                
                                    from f in info.GetFiles()

                                    where f.Extension ".doc" | f.Extension ".xml" 

                                    select f.Name).ToList<string>() ;



Whismeril
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
18 nov. 2012 à 13:38
Je préfère que la discussion ait lieu ici plutôt qu'en MP.

Evidement que mon code fait moins de choses, je t'ai montré une piste pas ton programme tout refait!
La recherche des doublons c'est assez simple, je vais te faire un exemple et le poster.
Le tri pareil.
L'affichage dans le datagridview, et bien à la fin de la recherche tu affectes la list<string> (ou autre objet) au datasource de la grille ou tu passe par un databindingsource, j'ai posté un tuto là dessus.
La sauvegarde dans un fichier xml, vu que tu as une List<T> tu perds du temps d'exécution à lire le datagridview, sérialize la liste directement. Il y a pleins d'exemple sur le forum, dont des miens.


L'affichage de la progresse bar, bon là avec linq je ne sais pas trop.



Whismeril
0
Rapakooti Messages postés 90 Date d'inscription mercredi 4 décembre 2002 Statut Membre Dernière intervention 18 mai 2018
18 nov. 2012 à 13:49
Pour ici lol pas de souci ca reviens au meme pour moi... oui ton compte fait moi de truc mais c est pas le souci je l'ai inteegre au pire apres je peux ajouter des fonctions, le souci c est que comme le code de BarthOlivier il ne s gere pas les lecteurs reseaux... et ca c est un gros souci car tous les repertoire scanne se trouve sur des lecteurs reseau

R A P A K O O T I
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
18 nov. 2012 à 14:10
Voila un nouvel exemple, j'appelle la fonction LanceDemo (je n'ai pas changé le nom du tuto), qui fait 3 recherches successives avec 4 répertoires, le premier y est toujours et les trois autres font l'objet d'un recherche à chaque fois.
Il y a donc des doublons qui sont traités et un lecteur réseau (enfin presque c'est un réseau virtualbox....).
Et tout ça trié par nom.


        public void LanceDemo()
        {


            DirectoryInfo[] infos = new DirectoryInfo[2];
            infos[0] = new DirectoryInfo(Application.StartupPath);
            infos[1] = new DirectoryInfo(@"c:\temp");

            List<string> liste1 = Recherche(infos, new List<string>());//récupére une première liste


            infos[1] = new DirectoryInfo(@"c:\temp2");//dans temps2  il y a le même doc que dans temp plus un second
            List<string> liste2 = Recherche(infos, liste1);//récupére la deuxième liste sans doublons


            infos[1] = new DirectoryInfo(@"e:\temp3");//e est un lecteur réseau
            List<string> liste3 = Recherche(infos, liste2);//récupére la troisième liste sans doublons
        }

        public List<string> Recherche(DirectoryInfo[] infos, List<string> existants)
        {
            List<string> query = (from info in infos
                
                                    from f in info.GetFiles()

                                    where f.Extension ".doc" | f.Extension ".xml" 

                                    orderby f.Name //tri par le nom
                                    select f.Name).ToList<string>();// retourne la liste de tous les doc et xml dans les répertoires contenus dans le tableau

            return existants.Union(query).ToList<string>();//la méthode d'extension de classe Union (issue de Linq) permet d'unir deux collections sans doublons, m^me si l'une est vide comme c'est le cas à la première recherche
        }



Whismeril
0
Rapakooti Messages postés 90 Date d'inscription mercredi 4 décembre 2002 Statut Membre Dernière intervention 18 mai 2018
18 nov. 2012 à 14:33
merci encore j'ai modifier ta procedure pour l'adapte ( juste extention) mais il me retourne rien sur mes lecteur reseau ,par contre effectivement autant pour moi pas de souci pour le C: je suis sous windows 8 s j'avais le soucis sous windows 7 avec directoryinfo


R A P A K O O T I
0
Rejoignez-nous