Récursiviter, lister les répertoires en C++

Signaler
Messages postés
20
Date d'inscription
vendredi 18 avril 2008
Statut
Membre
Dernière intervention
7 août 2009
-
Messages postés
20
Date d'inscription
vendredi 18 avril 2008
Statut
Membre
Dernière intervention
7 août 2009
-
Hello,

Merci de me lire,

excuser l'indentation des commentaires mai le copier coller déconne

pour le bug c'est simple c'est expliquer aux début du fichier

noter que je débute,depuis peux que je compile avec g++ j'utilise geany comme éditeur.

ce code est fonctionnel hormis le fait qu'il ne fait pas ce que je veux
Curieux il n'y a pas le moyen de coller son code ?
code

#include
#include <vector>
#include <string>
#include <dirent.h>
#include <sys/stat.h>
using std::string;
/*
 _______________________________
/______________________________/|
||    Coder par panthere noire   ||
||        liscence GPL v3        ||
|/_____________________________|/

Ce code est destiner a lister le plus rapidement possible.
Les fichier et les répertoire sous linux.
Avec leur atribbus aux complet.
 
*/

/*
Les répertoires ce présente comme ceci.
note: remplacer le ~ par celui de votre utilisateur.
mkdir -p ~/rep_racine/rep1
mkdir -p ~/rep_racine/rep2/sous_rep_2_0
mkdir -p ~/rep_racine/rep2/sous_rep_2_1
mkdir -p ~/rep_racine/rep2/sous_rep_2_2
mkdir -p ~/rep_racine/rep2/sous_rep_2_3
mkdir -p ~/rep_racine/rep3
mkdir -p ~/rep_racine/rep2/sous_rep_2_3/sous_sous_rep2
*
le dernier répertoir n'est pas trouver alors que ceux situer dans ~/rep_racine/rep2/ le son
*/
 
void Full_Search(std::vector<string> &search_full_path,
std::vector<string> &search_rep_name,
std::vector<string> &search_file_name,
std::vector<string> &stat_info,std::string &transfere);                                                //Prototype Full_Search

void Full_Search(std::vector<string> &search_full_path,
std::vector<string> &search_rep_name,
std::vector<string> &search_file_name,
std::vector<string> &stat_info, std::string &transfere)
{

    long number_element;                                                                            //déclaration, nombre d'element
    std::string source_transfere;                                                                    //déclaration, provisoire copie les donnée de la variable
    source_transfere = transfere;                                                                   
    number_element = search_full_path.size() -1;
        std::cout << "DEBUG ----------1: " << number_element << " :----------contien----------: "
         << search_full_path [number_element] << std::endl;
    if (source_transfere != "")
    {
        std::cout << "DEBUG ----------2: " << number_element << " :----------contien----------: "
        << search_full_path [number_element] << std::endl;
        int cmb = source_transfere.length();
        if (source_transfere.substr((cmb- 1), cmb) != "/")
        {
            source_transfere += "/";
            std::cout << "DEBUG ----------3: source_transfere :----------contien----------: "
            << source_transfere << std::endl;
        }
        DIR *InitialRep = opendir(source_transfere.c_str());
        if (InitialRep != NULL)
        {
            struct dirent *SRep;
            while ((SRep = readdir(InitialRep)) != NULL)                                            //tant que le répertoire contient des fichiers
            {
                string FileFound = SRep->d_name;                                                    //definir le fichier (dernier répertoir trouver)
                string PathFound = source_transfere + FileFound;                                    // chemin complet
                if (FileFound != "." && FileFound != "..")
                {   
                    source_transfere = PathFound;
                        FileFound = FileFound + "/";
                        search_full_path.push_back(FileFound);
                        ++number_element;
                        std::cout << "DEBUG ----------4: " << number_element <<
                        " :----------contien----------: " << FileFound << std::endl;
                        std::cout << "DEBUG ----------5: " << number_element <<
                        " :----------contien----------: " << search_full_path [number_element]
                        << std::endl;
                        if (opendir(PathFound.c_str()) != NULL)
                        {
                            std::cout << "DEBUG ----------6: " << number_element <<
                            " :----------contien----------: " << search_full_path [number_element]
                            << std::endl;
                            Full_Search(search_full_path, search_rep_name,
                            search_file_name, stat_info, source_transfere);                            //apelle recusif pour les sous répertoires bug ?
                            std::cout << "DEBUG ----------7: " << number_element
                            << " :----------contien----------: " << search_full_path [number_element]
                            << std::endl;
                        }
                }
                else                                                                                //else uniquement pour le debugage,il est possible de le supprimer
                {
                    std::cout << "DEBUG ----------8: " << number_element <<
                    " :----------contien----------: " << search_full_path [number_element]
                    << std::endl;
                    std::cout << "DEBUG ----------9: " << FileFound << std::endl;
                    std::cout << "DEBUG ----------10: " << transfere << std::endl;
                    std::cout << "DEBUG ----------11:: " << source_transfere << std::endl;
                   
                }
            } //while
        }
        closedir(InitialRep);                                                                        //fermer le repertoire courant
    }
}                                                                                                    //function Full_Search

int main()
{
                                                                                                    //variable
std::vector<std::string> search_full_path;                                                            //retourne un tableau chemin complet de tout les répertoires trouver
std::vector<std::string> search_rep_name;                                                             //repertoir seulement,pas encore utilisée
std::vector<std::string> search_file_name;                                                            //fichier seulement,pas encore utilisée
std::vector<std::string> stat_info;                                                                    //information global sur le répertoir ou le dossier,pas encore utilisée
std::string transfere;                                                                                //variable pour le nom du repertoir en recusiviter, passe en paramettre le répetoire racine.

                                                                                                    //code
                                                                                                   
search_full_path.push_back("/home/taz/rep_racine/");                                                //valeur par defaut,en cour de dévloppment,rarement utiliser
transfere = "/home/taz/rep_racine";
Full_Search(search_full_path, search_rep_name, search_file_name, stat_info,transfere);
std::cout << "nombre d'élément apres execution " << search_full_path.size() << std::endl;            //affiche le nombre d'entrée du tableau
    for (long i = 0; i < search_full_path.size(); ++i )                                             //affiche le contenu du tableaux
    {
        std::cout << search_full_path[i] << std::endl;
    }
std::cout << "affichage terminer" << std::endl;
return 0;
}                                                                                                    // main

6 réponses

Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
13
Salut,

[quote=panthere007]
Ce code est destiner a lister le plus rapidement possible.
/quote

Le plus rapidement possible ?

Alors tu n'emploies pas du tout la bonne méthode.

td::vector<string> -> string est lent. vector est lent. Combiné les deux c'est affreusement lent.

Et imagine que ton répertoire contienne 10000 répertoires ? Tu fait un vector de 10000 strings ?
Tu as une idée de la consommation mémoire ?
Bref, tu n'iras pas bien loin avec ce genre d'algo.

D'une manière générale quand on veut :
1) Récupérer un ensemble d'objets quelconques.
2) Appliquer un algo sur chacun d'entre eux.

Il ne faut pas essayer de lister ces objets puis parcourir ces objets.

Il faut faire le traitement a chaque objet lors du parcourt. C'est infiniment plus efficace.

Mais on voudrait ne pas avoir à réécrire l'algo de parcourt pour tous les traitements possibles.
Le copier coller, c'est mal.

On va donc faire une fonction de parcourt qui prend en argument une fonction (on appelle ça une callback) de traitement.

Comme ça la fonction de parcourt va appeler la fonction de traitement pour tous les élements parcouru.
Sans faire de liste ni autre structure mémoire aussi consommatrice de RAM que lente car allouée dynamiquement.

Voilà un exemple de code.

C'est du C. Ou du C++. Comme tu veux. Mais pour faire du "plus rapidement possible", je t'invite vivement à oublier le C++.
<hr size="2" width="100%" />#include <stdio.h>
#include <dirent.h>
#include <string.h>
 
/* Fonction callback appelée lors de l'énumération */
typedef int (*enum_dir_callback)(char *lpDirPath);

/*
 * Utilisée par EnumDir pour pouvoir transmettre un buffer en paramètre
 * et ainsi ne pas surchrager la pile.
 */
int EnumDirInternal(char *lpDirPath, enum_dir_callback lpCallback, char* lpBuffer)
{
  DIR *lpDir;               /* Le répertoire courant      */
  struct dirent *lpChild;   /* Un fils du répertoire      */
  int bContinue;            /* Continuer l'énumération ?  */
   
  bContinue = 1;
  lpDir = opendir(lpDirPath);

  /* Si c'est un répertoire */
  if (lpDir)
  {
    /* Appel de la fonction utilisateur */
    if (! lpCallback(lpDirPath))
      bContinue = 0;
    else
    {
      /* On récupère . et .. */
      readdir(lpDir);
      readdir(lpDir);

      /* Pour tous les fils */
      while (1)
      {
        lpChild = readdir(lpDir);
        if (! lpChild) break;

        /* Construction d'un chemin complet vers le fils */
        strcpy(lpBuffer, lpDirPath);
        strcat(lpBuffer, "/");
        strcat(lpBuffer, lpChild->d_name);

        /* Appel récursif */
        if (! EnumDirInternal(lpBuffer, lpCallback, lpBuffer))
        {
          bContinue = 0;
          break;
        }
      }
    }
    closedir(lpDir);
  }
  return bContinue;
}

/*
 * Appelle lpCallback pour lpDirPath et tous ses sous répertoires.
 * Arrête l'énumération si lpCallback renvoie 0.
 */
int EnumDir(char *lpDirPath, enum_dir_callback lpCallback)
{
  char lpFullPath[4096];

  return EnumDirInternal(lpDirPath, lpCallback, lpFullPath);
}

/*
 * Notre fonction qui sera appelée pour tous les répertoires.
 */
int DisplayDir(char *lpDirPath)
{
  printf("%s\n", lpDirPath);
  return 1;
}

int main(void)
{
  /* On appelle DisplayDir pour tous les sous répertoires de . */
  EnumDir(".", DisplayDir);

  return 0;
}
Messages postés
20
Date d'inscription
vendredi 18 avril 2008
Statut
Membre
Dernière intervention
7 août 2009

Merci pour ta réponse très constructives :)

Je ne connaissait pas les callback, je vai me panchez dessus

j'ai essayer ton code telle qu'elle , 2 bug voici la première erreur:

surf_find_file_main.cpp: In function ‘int main()’:

surf_find_file_main.cpp:80: warning: deprecated conversion from string constant to ‘char*’
./
./.

la 2eme j'ai change le chemin dans le main par /home/user/rep_racine user étant l'utilisateur et j'obtien
line 10:  5329 Erreur de segmentation

note je compile avec g++ ton code rassemble surtout a du C et pas du C++ (excuse pour la confusion c'est lier aux fait que j'utilise cout et pas printf.
Avec quoi l'a tu compiler ? gcc ?

Merci pour ta réponse :)
Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
13
Avec quoi l'a tu compiler ? gcc ?

Avec les deux en fait.


warning: deprecated conversion from string constant to 'char*'



Mais je n'ai pas eu ce warning. D'après le net, il n'apparait pas sur des versions anciennes. Il est en fait dû au fait que mon "." passé en paramètre de EnumDir est en lecture seule, et donc qu'il ne peut pas être passé en paramètre d'une fonction qui attend un char*. Il faut changer une ou deux signatures en ajoutant const.

line 10:  5329 Erreur de segmentation

Probablement un dépassement des 4096 caractères du tampon. Non pas que tu ais (Ou pas) un chemin de 4096 caractères dans ton home, il y a un bug dans mon source.

En effet, lors de l'appel à EnumDirInternal(lpBuffer, lpCallback, lpBuffer), lpBuffer était modifié pour ajouté un fils, ce qui modifiait aussi le lpDirPath puisqu'ils sont les mêmes lors de cette appel. Bilan cela concaténait le fils 1 avec le fils 2 et ainsi de suite. Donc ça ne listait pas la moitié des répertoires et ça faisait des chemins beaucoup trops longs -> d'où l'erreur de segmentation je pense.

Donc il faut remonter d'un répertoire en sortie d'appel à EnumDirInternal.

Voilà qui devrait aller mieux :
<hr size="2" width="100%" />#include <stdio.h>
#include <dirent.h>
#include <string.h>
 
/* Fonction callback appelée lors de l'énumération */
typedef int (*enum_dir_callback)(const char *lpDirPath);

/*
 * Utilisée par EnumDir pour pouvoir un premier caractère non const.
 */
int EnumDirInternal(char *lpDirPath, enum_dir_callback lpCallback)
{
  DIR *lpDir;               /* Le répertoire courant      */
  struct dirent *lpChild;   /* Un fils du répertoire      */
  int bContinue;            /* Continuer l'énumération ?  */
   
  bContinue = 1;
  lpDir = opendir(lpDirPath);
 
  /* Si c'est un répertoire */
  if (lpDir)
  {
    /* Appel de la fonction utilisateur */
    if (! lpCallback(lpDirPath))
      bContinue = 0;
    else
    {
      /* On récupère . et .. */
      readdir(lpDir);
      readdir(lpDir);

      /* Pour tous les fils */
      while (1)
      {
        lpChild = readdir(lpDir);
        if (! lpChild) break;

        /* Construction d'un chemin complet vers le fils */
        strcat(lpDirPath, "/");
        strcat(lpDirPath, lpChild->d_name);

        /* Appel récursif */
        if (! EnumDirInternal(lpDirPath, lpCallback))
        {
          bContinue = 0;
          break;
        }
        /* Récupération du parent */
        strrchr(lpDirPath, '/')[0] = '\0';
      }
    }
    closedir(lpDir);
  }
  return bContinue;
}

/*
 * Appelle lpCallback pour lpDirPath et tous ses sous répertoires.
 * Arrête l'énumération si lpCallback renvoie 0.
 */
int EnumDir(const char *lpDirPath, enum_dir_callback lpCallback)
{
  char lpPath[4096];

  strcpy(lpPath, lpDirPath);
  return EnumDirInternal(lpPath, lpCallback);
}

/*
 * Notre fonction qui sera appelée pour tous les répertoires.
 */
int DisplayDir(const char *lpDirPath)
{
  printf("%s\n", lpDirPath);
  return 1;
}

int main(void)
{
  /* On appelle DisplayDir pour tous les sous répertoires de . */
  EnumDir("/home/brbo/dml-mapper", DisplayDir);

  return 0;
}
Messages postés
20
Date d'inscription
vendredi 18 avril 2008
Statut
Membre
Dernière intervention
7 août 2009

merci pour ta réponse, ma sa bug toujours :s

voila un extrait de la sortie  le  ~ = /home/tonuser
~/rep_racine/rep3/./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././sous_rep3_2_2

sa me fait pareil si je mai le répertoire /home donc je doit dire que j'ai un peux de pain a suivre
Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
13
Hein ???

Eventuellement, il peut y avoir un problème avec une arborescence récursive, c'est à dire un link avec un répertoire parent. Mais ta sortie est bizarre.

Tu as essayé sur une arborescence de répertoires plus simple ?

Au vu de la sortie, peut être que "." et ".." ne sont pas les deux premiers répertoires listés... Essaie de remplacer EnumDirInternal par cette fonction (Non testée) :

/*
 * Utilisée par EnumDir pour pouvoir un premier caractère non const.
 */
int EnumDirInternal(char *lpDirPath, enum_dir_callback lpCallback)
{
  DIR *lpDir;               /* Le répertoire courant      */
  struct dirent *lpChild;   /* Un fils du répertoire      */
  int bContinue;            /* Continuer l'énumération ?  */
   
  bContinue = 1;
  lpDir = opendir(lpDirPath);
 
  /* Si c'est un répertoire */
  if (lpDir)
  {
    /* Appel de la fonction utilisateur */
    if (! lpCallback(lpDirPath))
      bContinue = 0;
    else
    {
      /* Pour tous les fils */
      while (1)
      {
        lpChild = readdir(lpDir);
        if (! lpChild) break;
        if (! strcmp(lpChild->d_name, ".") continue;
        if (! strcmp(lpChild->d_name, "..") continue;

        /* Construction d'un chemin complet vers le fils */
        strcat(lpDirPath, "/");
        strcat(lpDirPath, lpChild->d_name);

        /* Appel récursif */
        if (! EnumDirInternal(lpDirPath, lpCallback))
        {
          bContinue = 0;
          break;
        }
        /* Récupération du parent */
        strrchr(lpDirPath, '/')[0] = '\0';
      }
    }
    closedir(lpDir);
  }
  return bContinue;
}
Messages postés
20
Date d'inscription
vendredi 18 avril 2008
Statut
Membre
Dernière intervention
7 août 2009

merci pour ta réponse , j'ai pas essayer t'a denière méthode methode, mai je m'en suis inspirer.
le code que je fourni ici fonctionne chez moi, note que le tableau de type vector est facultatif. sinon sa tourne bien.

si tu as une remarque je suis velontaire

code:
#include
#include <vector>
#include <string>
#include <dirent.h>
#include <sys/stat.h>
using std::string;

void search_find_file_dir(std::string *,std::vector<string> &done_rep_only);

void search_find_file_dir(std::string *dir_source,std::vector<string> &done_rep_only)
{
    //variable
    DIR *pointeur_flux_dir;
    struct dirent *pointeur_flux_file;
    std:string read_flux_file;
    std::string N="";
    //code
    std::cout << "Le chemin d'acès est: "<< *dir_source << " L'adresse du pointeur est: " << dir_source << std::endl;
    pointeur_flux_dir = opendir((*dir_source).c_str());
    if (pointeur_flux_dir == NULL)
    {
        return;
    }
    while ((pointeur_flux_file = readdir(pointeur_flux_dir)) != NULL)
    {
        read_flux_file = pointeur_flux_file->d_name;        if ( read_flux_file "." || read_flux_file "..")
        {   
            continue;
        }
        if (pointeur_flux_file->d_type == DT_DIR) {
        std::cout << pointeur_flux_file->d_name << std::endl;
        N=*dir_source + "/" + pointeur_flux_file->d_name;
        done_rep_only.push_back(N);
        search_find_file_dir(&N,done_rep_only);
        }
        else
        {
        std::cout << "N'est pas un répertoire: " << pointeur_flux_file->d_name << std::endl;
        }
    }
}
int main()
{
    std::vector<std::string> done_rep_only;
    std::cout << "Démmarage de la recherche des répertoires" << std::endl;
    std::string p;
    p = "/home/taz/rep_racine";
    search_find_file_dir(&p,done_rep_only);
    //affiche le contenu du tableaux
    for (long i = 0; i < done_rep_only.size(); ++i )
    {
        std::cout << done_rep_only[i] << std::endl;
    }
    std::cout << "affichage terminer" << std::endl;
    return 0;
}