Partage
  • Partager sur Facebook
  • Partager sur Twitter

dirent.h - choisir les dossiers

    10 octobre 2019 à 5:22:59

    Bonjour
    J'utilise `dirent.h' et les fonctions d'accès aux dossiers (directory) telles que `opendir' et `readdir'.
    Je suis sur Windows et je ne vois rien dans la structure `dirent' qui pourrait m'indiquer si l'élément lu par `readdir' est un dossier ou un fichier.
    On suggère de vérifier l'extension mais il y a des fichiers sans extension et des dossiers avec extension.
    Je ne veux pas me taper les quelques 500 types d'extensions supportées par Windows.
    On suggère aussi d'ouvrir avec `opendir' cet élément et si le pointeur retourné est NULL, c'est un fichier.
    Le problème est que `opendir' peut retourner NULL pour d'autres raisons.
    Alors, comment je fais pour savoir si l'élément est un fichier ou un dossier?
    Merci pour toute information.
    • Partager sur Facebook
    • Partager sur Twitter

    Le Tout est souvent plus grand que la somme de ses parties.

      10 octobre 2019 à 12:46:52

      Regarde la fonction 'stat', elle te permet d'obtenir des informations sur un fichier. Et comme les dossiers sont des fichiers (un peu particuliers) tu devrais pouvoir résoudre ton problème.
      • Partager sur Facebook
      • Partager sur Twitter
        10 octobre 2019 à 16:18:24

        Salut,

        dirent.h est une API POSIX (idem pour stat) et n'est donc pas officiellement supportée par Windows. D'ailleurs sur Visual Studio cet entête n'existe pas.

        Normalement, sous Windows on utilise FindFirstFile/FindNextFile.

        En revanche, stat existe, mais pas fstatat non plus.

        -
        Edité par markand 10 octobre 2019 à 16:18:59

        • Partager sur Facebook
        • Partager sur Twitter

        git is great because Linus did it, mercurial is better because he didn't.

          11 octobre 2019 à 7:32:27

          Bonjour
          J'ai consulté la page suivante:
          http://manpagesfr.free.fr/man/man2/stat.2.html
          Si j'imprime `buf.st_mode' en octal, j'obtient:
          100777 pour les fichiers et les dossiers
          100666 pour les liens symboliques (raccourcis).
          Ce n'est pas très utile pour savoir si c'est un dossier.
          Par contre, je suppose que les `777' et `666' représentent les permissions.
          Un raccourci n'a pas la permission de s'exécuter ou être parcouru, il est seulement lu par l'explorateur de fichiers.
          Pour `C:\Windows' j'obtient:
          040777 c'est un dossier protégé ...
          Je pense que les fonctions FindFirstFile et FindNextFile ne sont disponibles que pour C++
          De toute façon, elles laissent supposer que l'on ne regarde que les fichiers, on saute les dossiers.
          Je suis revenu à la case départ ...
          • Partager sur Facebook
          • Partager sur Twitter

          Le Tout est souvent plus grand que la somme de ses parties.

            11 octobre 2019 à 9:07:49

            C'est parce que ce sont des flags. Tu n'es pas censé vérifier directement st_mode mais utiliser les macros comme décrit dans le manuel. L'entier st_mode contient plus d'informations que juste le type, grâces aux flags on peut les combiner. st_mode peut te dire que le type est un répertoire en plus de te donner ses permissions.

            if (S_ISDIR(buf.st_mode)) {
                puts("c'est un répertoire");
            
                // exemple sous unix...
                if (buf.st_mode & S_IXUSR)
                    puts("le propriétaire a le mode exécutable");
                if (buf.st_mode & S_IXGRP)
                    puts("le groupe a le mode exécutable");
                if (buf.st_mode & S_IXOTH)
                    puts("les autres ont le mode exécutable");
            }

            Je n'ai pas compris ce que tu veux dire pour FindFirstFile/FindNextFile. Ça fait parti de l'API Windows qui est en C.

            -
            Edité par markand 11 octobre 2019 à 10:20:56

            • Partager sur Facebook
            • Partager sur Twitter

            git is great because Linus did it, mercurial is better because he didn't.

              11 octobre 2019 à 14:52:10

              Désolé, je ne sais pas ce que veux dire l'acronyme `API'?
              Ensuite, j'ai refait mes tests, j'ai dû faire une erreur, pour les dossiers, j'ai:
              040777
              et pour les fichiers ordinaires:
              100666
              les exécutables sont à:
              100777
              Les raccourcis sont encore à:
              100666
              Je suppose que Windows regarde l'extension `.lnk'.
              Je n'ai pas trouvé le header où se trouvent ces macros et ces flags. Ils ne sont pas dans les trois mentionnés dans la doc.
              J'utilise:
              #include <sys/types.h>
              #include <sys/stat.h>
              #include <unistd.h>
              #include <stdio.h>  // Pour les printf
              #include <errno.h>  //Pour perror()
              Avez-vous une idée où ça se trouve?
              • Partager sur Facebook
              • Partager sur Twitter

              Le Tout est souvent plus grand que la somme de ses parties.

                12 octobre 2019 à 16:24:31

                J'ai revisé mon environnement de travail.
                J'ai refait le test de mon message précédent et je peux effectivement savoir si j'ai un dossier ou un fichier.
                La macro `S_ISDIR(m)' existe bien et fonctionne conformément à la doc mentionnée.
                Je rappelle que je suis sur Windows 10.
                J'utilise `gcc' du package MinGW-w64 de sourceforge.
                • Partager sur Facebook
                • Partager sur Twitter

                Le Tout est souvent plus grand que la somme de ses parties.

                  13 octobre 2019 à 19:20:54

                  Euréka! Je viens de trouver que API veut dire Application Program Interface. Je l'utilisais sans même le savoir ...
                  Il y a un petit problème d'incompatibilité entre les fonctions opendir/readdir/closedir et les fonctions `stat' et `_stat'.
                  Je m'explique:
                  `opendir' un ouvre un dossier qui n'a pas besoin d'être un fils du dossier courant (chemin absolu).
                  Alors que `stat' et `_stat' se refèrent à autre chose que l'entrée fournie par `readdir'.
                  Si j'ai un dossier qui contient environ 2000 entités, chaque appel à `stat' exige que le système parcourt tout le dossier pour retrouver l'entrée que je venais de rencontrer.
                  Si je regarde la structure `dirent', j'obtient:
                  struct dirent{
                  long d_ino; // Se refère au `inode' de Unix/Linux?
                  unsigned short d_reclen; // Longueur du descripteur du dossier?
                  unsigned short d_namlen; // Inutile si le nom se termine par un zéro.
                  char d_name[260]; // l'information la plus utile
                  };
                  D'après mes recherches, `d_name ne devrait pas avoir plus de 256 caractères plus le zéro de fin de chaîne.
                  La longueur totale d'un chemin est 32767 plus le zéro sur Windows.
                  Si `stat' et `_stat' se reféraient au `inode', on sauverait du temps.
                  Je ne sais pas ce qu'il y a dans le champ `d_ino'. C'est un `long', pas un pointeur vers une structure.
                  À part cela, je peux obtenir l'information que je veux en faisant attention aux noms que je donne à `opendir', `stat' et `_stat'.
                  • Partager sur Facebook
                  • Partager sur Twitter

                  Le Tout est souvent plus grand que la somme de ses parties.

                    14 octobre 2019 à 9:14:14

                    stat, opendir, open, fopen, toutes ces fonctions utilisent le chemin tel quel. C'est à dire s'il est relatif c'est par rapport au répertoire courant, sinon le chemin absolu.

                    En revanche, la fonction POSIX fstatat permet d'ouvrir le fichier relativement au répertoire passé en argument (mais avec opendir tu reçois un DIR* et non un file descripteur). En bref en utilisant totalement l'API POSIX on peut parcourir des sous répertoire sans jamais utiliser de chemin sous forme de chaîne de caractère et c'est super élégant.

                    // bien sûr, il faut tester les retour...
                    int dfd = open("repertoire_de_base", O_RDONLY);
                    DIR *dp = fdopendir(dfd);
                    struct dirent *ent;
                    
                    while ((ent = readdir(dp))) {
                        // ici, fstatat va ouvrir implicitement "repertoire_de_base/<ent->d_name>"
                        struct stat st;
                        int fd = fstatat(dfd, ent->d_name, &st, 0);
                    }
                    

                    En fait, beaucoup de fonctions POSIX se finissant par "at" signifie « relatif au file descripteur du répertoire ».

                    Mais c'est du POSIX et donc non supporté nativement sur Windows.

                    • Partager sur Facebook
                    • Partager sur Twitter

                    git is great because Linus did it, mercurial is better because he didn't.

                      14 octobre 2019 à 23:26:06

                      En fait, j'avais compris l'histoire des chemins relatifs et absolus dans `opendir' et `stat'.
                      Ce qui me dérange, c'est que `stat' va lire tout le répertoire pour retrouver l'entrée que je viens de trouver avec `readdir'.
                      Comme je l'ai dit, si `d_ino' pointait vers le `inode' ou l'équivalent pour Windows, ce serait beaucoup plus efficace.
                      Je n'ai pas lu la doc de `fstatart', mais il semble que ce soit la même chose. Elle va lire tout le répertoire pour retrouver mon entrée.
                      Je me demande s'il existe, même sur Linux, une telle possibilité?
                      • Partager sur Facebook
                      • Partager sur Twitter

                      Le Tout est souvent plus grand que la somme de ses parties.

                      dirent.h - choisir les dossiers

                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                      • Editeur
                      • Markdown