web-dev-qa-db-fra.com

C ++ - Déterminer si un répertoire (pas un fichier) existe sous Linux

Comment pourrais-je déterminer si un répertoire (pas un fichier) existait en utilisant C++ sous Linux? J'ai essayé d'utiliser la fonction stat () mais elle est retournée positive lorsqu'un fichier a été trouvé. Je veux seulement trouver si la chaîne entrée est un répertoire, pas autre chose.

23
MetaDark

Selon man (2) stat vous pouvez utiliser la macro S_ISDIR sur le champ st_mode:

bool isdir = S_ISDIR(st.st_mode);

Remarque: je recommanderais d'utiliser Boost et/ou Qt4 pour faciliter la prise en charge multiplateforme si votre logiciel peut être viable sur d'autres systèmes d'exploitation.

29
OneOfOne

que diriez-vous de quelque chose que j'ai trouvé ici

#include <dirent.h>

bool DirectoryExists( const char* pzPath )
{
    if ( pzPath == NULL) return false;

    DIR *pDir;
    bool bExists = false;

    pDir = opendir (pzPath);

    if (pDir != NULL)
    {
        bExists = true;    
        (void) closedir (pDir);
    }

    return bExists;
}

Ou en utilisant stat

struct stat st;
if(stat("/tmp",&st) == 0)
    if(st.st_mode & S_IFDIR != 0)
        printf(" /tmp is present\n");
15
ayush

Si vous pouvez consulter la bibliothèque de systèmes de fichiers boost . C'est un excellent moyen de traiter ce type de problèmes de manière générique et portable.

Dans ce cas, il suffirait d'utiliser:

#include "boost/filesystem.hpp"   
using namespace boost::filesystem; 
...
if ( !exists( "test/mydir" ) ) {bla bla}
10
Dr G

Voici comment je comprends votre question: vous avez un chemin, par exemple, /foo/bar/baz (baz est un fichier) et vous voulez savoir si /foo/bar existe. Si c'est le cas, la solution ressemble à ceci (non testé):

char *myDir = dirname(myPath);
struct stat myStat;
if ((stat(myDir, &myStat) == 0) && (((myStat.st_mode) & S_IFMT) == S_IFDIR)) {
    // myDir exists and is a directory.
}
6
DarkDust

Si vous voulez savoir si un répertoire existe parce que vous voulez en faire quelque chose (créez un fichier/répertoire à l'intérieur, scannez son contenu, etc.), vous devez simplement continuer et faire ce que vous voulez, puis vérifiez s'il a échoué, et si oui, signalez strerror(errno) à l'utilisateur. C'est un principe général de programmation sous Unix: n'essayez pas de savoir si la chose que vous voulez faire fonctionnera. Essayez-le, puis voyez s'il a échoué.

Si vous voulez vous comporter spécialement si quelque chose a échoué parce qu'un répertoire n'existait pas (par exemple, si vous voulez créer un fichier et tous les répertoires contenant nécessaires), vous recherchez errno == ENOENT après open échoue.

Je constate qu'un répondant a recommandé l'utilisation de boost::filesystem. Je voudrais comme pour approuver cette recommandation, mais malheureusement je ne peux pas, car boost::filesystem n'est pas uniquement en-tête, et tous les modules non-en-tête de Boost ont un bilan horrible de causant des ruptures mystérieuses si vous mettez à niveau la bibliothèque partagée sans recompiler l'application, ou même si vous n'avez tout simplement pas réussi à compiler votre app avec exactement les mêmes indicateurs utilisés pour compiler la bibliothèque partagée. Le chagrin d'entretien n'en vaut tout simplement pas la peine.

1
zwol

En C++ 17 **, std::filesystem fournit deux variantes pour déterminer l'existence d'un chemin:

  1. is_directory() détermine si un chemin est un répertoire et existe dans le système de fichiers réel
  2. exists() détermine simplement si le chemin existe dans le système de fichiers réel (sans vérifier s'il s'agit d'un répertoire)

Exemple (sans gestion d'erreur):

#include <iostream>
#include <filesystem> // C++17
//#include <experimental/filesystem> // C++14
namespace fs = std::filesystem;
//namespace fs = std::experimental::filesystem; // C++14

int main()
{
    // Prepare.
    const auto processWorkingDir = fs::current_path();
    const auto existingDir = processWorkingDir / "existing/directory"; // Should exist in file system.
    const auto notExistingDir = processWorkingDir / "fake/path";
    const auto file = processWorkingDir / "file.ext"; // Should exist in file system.

    // Test.
    std::cout
        << "existing dir:\t" << fs::is_directory(existingDir) << "\n"
        << "fake dir:\t" << fs::is_directory(notExistingDir) << "\n"
        << "existing file:\t" << fs::is_directory(file) << "\n\n";

    std::cout
        << "existing dir:\t" << fs::exists(existingDir) << "\n"
        << "fake dir:\t" << fs::exists(notExistingDir) << "\n"
        << "existing file:\t" << fs::exists(file);
}

Sortie possible:

existing dir:   1
fake dir:       0
existing file:  0

existing dir:   1
fake dir:       0
existing file:  1

** en C++ 14 std::experimental::filesystem est disponible


Les deux fonctions lancent filesystem_error en cas d'erreur. Si vous voulez éviter d'attraper des exceptions, utilisez les variantes surchargées avec std::error_code comme deuxième paramètre.

#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;

bool isExistingDir(const fs::path& p) noexcept
{
    try
    {
        return fs::is_directory(p);
    }
    catch (std::exception& e)
    {
        // Output the error message.
        const auto theError = std::string{ e.what() };
        std::cerr << theError;

        return false;
    }
}

bool isExistingDirEC(const fs::path& p) noexcept
{
    std::error_code ec;
    const auto isDir = fs::is_directory(p, ec);
    if (ec)
    {
        // Output the error message.
        const auto theError = ec.message();
        std::cerr << theError;

        return false;
    }
    else
    {
        return isDir;
    }
}

int main()
{
    const auto notExistingPath = fs::path{ "\xa0\xa1" };
    isExistingDir(notExistingPath);
    isExistingDirEC(notExistingPath);
}
1
Roi Danton