Le moyen le plus rapide de vérifier si un fichier existe en utilisant le standard C ++ / C ++ 11 / C?

Je voudrais trouver le moyen le plus rapide de vérifier si un fichier existe en standard en C ++ 11, C ++ ou C. J’ai des milliers de fichiers et avant de faire quelque chose, je dois vérifier s’ils existent tous. Que puis-je écrire à la place de /* SOMETHING */ dans la fonction suivante?

 inline bool exist(const std::ssortingng& name) { /* SOMETHING */ } 

    Eh bien, j’ai rassemblé un programme de test qui a exécuté chacune de ces méthodes 100 000 fois, la moitié sur des fichiers qui existaient et l’autre moitié sur des fichiers qui ne l’étaient pas.

     #include  #include  #include  inline bool exists_test0 (const std::ssortingng& name) { ifstream f(name.c_str()); return f.good(); } inline bool exists_test1 (const std::ssortingng& name) { if (FILE *file = fopen(name.c_str(), "r")) { fclose(file); return true; } else { return false; } } inline bool exists_test2 (const std::ssortingng& name) { return ( access( name.c_str(), F_OK ) != -1 ); } inline bool exists_test3 (const std::ssortingng& name) { struct stat buffer; return (stat (name.c_str(), &buffer) == 0); } 

    Résultats pour le temps total nécessaire pour exécuter les 100 000 appels en moyenne sur 5 cycles,

     Method exists_test0 (ifstream): **0.485s** Method exists_test1 (FILE fopen): **0.302s** Method exists_test2 (posix access()): **0.202s** Method exists_test3 (posix stat()): **0.134s** 

    La fonction stat() fourni les meilleures performances sur mon système (Linux, compilé avec g ++), un appel standard fopen étant votre meilleur choix si, pour une raison quelconque, vous refusez d’utiliser les fonctions POSIX.

    J’utilise ce morceau de code, ça marche bien avec moi jusqu’à présent. Cela n’utilise pas beaucoup de fonctionnalités sophistiquées de C ++:

     bool is_file_exist(const char *fileName) { std::ifstream infile(fileName); return infile.good(); } 

    Remarque: en C ++ 14 et dès que le système de fichiers TS sera terminé et adopté, la solution sera d’utiliser:

     std::experimental::filesystem::exists("helloworld.txt"); 

    et depuis C ++ 17, uniquement:

     std::filesystem::exists("helloworld.txt"); 

    Cela dépend de l’emplacement des fichiers. Par exemple, s’ils sont tous supposés être dans le même répertoire, vous pouvez lire toutes les entrées du répertoire dans une table de hachage, puis vérifier tous les noms sur la table de hachage. Cela peut être plus rapide sur certains systèmes que de vérifier chaque fichier individuellement. Le moyen le plus rapide de vérifier chaque fichier individuellement dépend de votre système … si vous écrivez C ANSI, le moyen le plus rapide est de le faire car c’est le seul moyen (un fichier peut exister mais ne peut pas être ouvert) vous devez “faire quelque chose”. C ++, POSIX, Windows offrent tous des options supplémentaires.

    Pendant que j’y suis, laissez-moi vous signaler quelques problèmes avec votre question. Vous dites que vous voulez le moyen le plus rapide et que vous avez des milliers de fichiers, mais vous demandez alors le code d’une fonction pour tester un seul fichier (et cette fonction est uniquement valide en C ++, pas en C). Cela contredit vos exigences en faisant une hypothèse sur la solution … un cas de problème XY . Vous dites aussi “en standard c ++ 11 (ou) c ++ (ou c) … qui sont tous différents, et cela est également incompatible avec vos exigences en matière de vitesse … la solution la plus rapide impliquerait d’adapter le code au système cible. L’incohérence de la question est soulignée par le fait que vous avez accepté une réponse qui donne des solutions dépendantes du système et qui ne sont pas standard C ou C ++.

    Pour ceux qui aiment boost:

      boost::filesystem::exists(fileName) 

    Sans utiliser d’autres bibliothèques, j’aime utiliser l’extrait de code suivant:

     #ifdef _WIN32 #include  #define access _access_s #else #include  #endif bool FileExists( const std::ssortingng &Filename ) { return access( Filename.c_str(), 0 ) == 0; } 

    Cela fonctionne multi-plateforme pour les systèmes compatibles Windows et POSIX.

    Idem suggéré par PherricOxide mais en C

     #include  int exist(const char *name) { struct stat buffer; return (stat (name, &buffer) == 0); } 
     inline bool exist(const std::ssortingng& name) { ifstream file(name); if(!file) // If the file was not found, then file is 0, ie !file=1 or true. return false; // The file was not found. else // If the file was found, then file is non-0. return true; // The file was found. } 

    Trois autres options sous Windows:

    1

     inline bool exist(const std::ssortingng& name) { OFSTRUCT of_struct; return OpenFile(name.c_str(), &of_struct, OF_EXIST) != INVALID_HANDLE_VALUE && of_struct.nErrCode == 0; } 

    2

     inline bool exist(const std::ssortingng& name) { HANDLE hFile = CreateFile(name.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != NULL && hFile != INVALID_HANDLE) { CloseFile(hFile); return true; } return false; } 

    3

     inline bool exist(const std::ssortingng& name) { return GetFileAtsortingbutes(name.c_str()) != INVALID_FILE_ATTRIBUTES; } 

    Vous pouvez aussi faire bool b = std::ifstream('filename').good(); . Sans les instructions de twigment (comme si), il doit fonctionner plus rapidement car il doit être appelé des milliers de fois.

    Si vous devez faire la distinction entre un fichier et un répertoire, considérez les éléments suivants, qui utilisent tous deux stat, l’outil standard le plus rapide, comme démontré par PherricOxide:

     #include  int FileExists(char *path) { struct stat fileStat; if ( stat(path, &fileStat) ) { return 0; } if ( !S_ISREG(fileStat.st_mode) ) { return 0; } return 1; } int DirExists(char *path) { struct stat fileStat; if ( stat(path, &fileStat) ) { return 0; } if ( !S_ISDIR(fileStat.st_mode) ) { return 0; } return 1; } 
     all_of (begin(R), end(R), [](auto&p){ exists(p); }) 

    R est votre séquence de choses ressemblant à un chemin, et exists() provient du boost std ou current futur. Si vous lancez le vôtre, restz simple,

     bool exists (ssortingng const& p) { return ifstream{p}; } 

    La solution ramifiée n’est pas absolument terrible et ne gobera pas les descripteurs de fichiers,

     bool exists (const char* p) { #if defined(_WIN32) || defined(_WIN64) return p && 0 != PathFileExists (p); #else struct stat sb; return p && 0 == stat (p, &sb); #endif } 

    Vous pouvez utiliser std::ifstream , funcion comme is_open , fail , par exemple comme ci-dessous le code (le cout “open” signifie que le fichier existe ou non):

    entrer la description de l'image ici

    entrer la description de l'image ici

    cité de cette réponse

    L’utilisation de MFC est possible avec les éléments suivants

     CFileStatus FileStatus; BOOL bFileExists = CFile::GetStatus(FileName,FileStatus); 

    FileName est une chaîne représentant le fichier que vous vérifiez d’existance

    J’ai besoin d’une fonction rapide capable de vérifier si un fichier existe ou non et la réponse de PherricOxide est presque ce dont j’ai besoin, sauf qu’il ne compare pas les performances de boost :: filesystem :: exist et des fonctions ouvertes. À partir des résultats de référence, nous pouvons facilement voir que:

    • L’utilisation de la fonction stat est le moyen le plus rapide de vérifier si un fichier existe. Notez que mes résultats sont cohérents avec ceux de la réponse de PherricOxide.

    • La performance de la fonction boost :: filesystem :: exist est très proche de celle de la fonction stat et est également portable. Je recommanderais cette solution si les bibliothèques boost sont accessibles depuis votre code.

    Résultats de référence obtenus avec le kernel Linux 4.17.0 et gcc-7.3:

     2018-05-05 00:35:35 Running ./filesystem Run on (8 X 2661 MHz CPU s) CPU Caches: L1 Data 32K (x4) L1 Instruction 32K (x4) L2 Unified 256K (x4) L3 Unified 8192K (x1) -------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------- use_stat 815 ns 813 ns 861291 use_open 2007 ns 1919 ns 346273 use_access 1186 ns 1006 ns 683024 use_boost 831 ns 830 ns 831233 

    Voici mon code de référence:

     #include  #include  #include  #include  #include  #include  #include  #include  #include "boost/filesystem.hpp" #include  const std::ssortingng fname("filesystem.cpp"); struct stat buf; // Use stat function void use_stat(benchmark::State &state) { for (auto _ : state) { benchmark::DoNotOptimize(stat(fname.data(), &buf)); } } BENCHMARK(use_stat); // Use open function void use_open(benchmark::State &state) { for (auto _ : state) { int fd = open(fname.data(), O_RDONLY); if (fd > -1) close(fd); } } BENCHMARK(use_open); // Use access function void use_access(benchmark::State &state) { for (auto _ : state) { benchmark::DoNotOptimize(access(fname.data(), R_OK)); } } BENCHMARK(use_access); // Use boost void use_boost(benchmark::State &state) { for (auto _ : state) { boost::filesystem::path p(fname); benchmark::DoNotOptimize(boost::filesystem::exists(p)); } } BENCHMARK(use_boost); BENCHMARK_MAIN(); 

    En C ++ 17:

     #include  bool is_file_exist(std::ssortingng& str) { namespace fs = std::experimental::filesystem; fs::path p(str); return fs::exists(p); } 

    Bien qu’il y ait plusieurs manières de faire cela, la solution la plus efficace à votre problème serait probablement d’utiliser l’une des méthodes prédéfinies du fstream, comme good () . Avec cette méthode, vous pouvez vérifier si le fichier que vous avez spécifié existe ou non.

     fstream file("file_name.txt"); if (file.good()) { std::cout < < "file is good." << endl; } else { std::cout << "file isnt good" << endl; } 

    J'espère que vous trouvez ça utile.