Schnellste Möglichkeit, um zu überprüfen, ob eine Datei mit C ++ / C ++ 11 / C existiert?

Ich würde gerne den schnellsten Weg finden, um zu überprüfen, ob eine Datei in C ++ 11, C ++ oder C existiert. Ich habe Tausende von Dateien und bevor ich etwas an ihnen mache, muss ich prüfen, ob alle vorhanden sind. Was kann ich anstelle von /* SOMETHING */ in der folgenden function schreiben?

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

Nun, ich habe ein Testprogramm zusammengestellt, bei dem jede dieser Methoden 100.000 mal ausgeführt wurde, die Hälfte bei Dateien, die existierten, und die andere bei Dateien, die nicht existierten.

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

Ergebnisse für die Gesamtzeit für die Ausführung der 100.000 Anrufe, gemittelt über 5 Läufe,

 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** 

Die function stat() bot die beste performance auf meinem System (Linux, kompiliert mit g ++), wobei ein Standard-fopen-Aufruf die beste Wahl ist, wenn Sie aus irgendeinem Grund die Verwendung von POSIX-functionen ablehnen.

Ich benutze dieses Stück Code, es funktioniert soweit bei mir OK. Dies verwendet nicht viele ausgefallene functionen von C ++:

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

Bemerkung: in C ++ 14 und sobald der Dateisystem-TS beendet und übernommen wird, wird die Lösung sein:

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

und seit C ++ 17 nur:

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

Es hängt davon ab, wo sich die Dateien befinden. Wenn sie sich zum Beispiel alle im selben Verzeichnis befinden, können Sie alle Verzeichniseinträge in eine Hash-Tabelle lesen und dann alle Namen in der Hash-Tabelle überprüfen. Dies kann auf manchen Systemen schneller sein als jede Datei einzeln zu prüfen. Der schnellste Weg, um jede Datei einzeln zu überprüfen, hängt von Ihrem System ab … Wenn Sie ANSI C schreiben, ist der schnellste Weg fopen weil es die einzige Möglichkeit ist (eine Datei existiert zwar, ist aber nicht zu öffnen, aber Sie wollen wahrscheinlich wirklich geöffnet werden) Sie müssen etwas tun “). C ++, POSIX, Windows bieten alle zusätzliche Optionen.

Während ich dabei bin, lassen Sie mich auf einige Probleme mit Ihrer Frage hinweisen. Sie sagen, dass Sie den schnellsten Weg wollen, und dass Sie Tausende von Dateien haben, aber dann fragen Sie nach dem Code für eine function, um eine einzelne Datei zu testen (und diese function ist nur in C ++ und nicht in C gültig). Dies widerspricht Ihren Anforderungen, indem Sie eine Annahme über die Lösung machen … einen Fall des XY-Problems . Sie sagen auch “in Standard C ++ 11 (oder) C ++ (oder) C” … die alle unterschiedlich sind, und dies ist auch nicht im Einklang mit Ihrer Anforderung für die Geschwindigkeit … die schnellste Lösung wäre die Anpassung des Codes an die Zielsystem. Die Inkonsistenz in der Frage wird durch die Tatsache hervorgehoben, dass Sie eine Antwort akzeptierten, die Lösungen gibt, die systemabhängig sind und nicht Standard C oder C ++ sind.

Für diejenigen, die Boost mögen:

  boost::filesystem::exists(fileName) 

Ohne andere Bibliotheken zu verwenden, verwende ich gerne das folgende Code-Snippet:

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

Dies funktioniert plattformübergreifend für Windows und POSIX-konforme Systeme.

Das gleiche wie von PherricOxid, aber in C vorgeschlagen

 #include  int exist(const char *name) { struct stat buffer; return (stat (name, &buffer) == 0); } 
 inline bool exist(const std::string& 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. } 

Weitere 3 Optionen unter Windows:

1

 inline bool exist(const std::string& 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::string& 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::string& name) { return GetFileAttributes(name.c_str()) != INVALID_FILE_ATTRIBUTES; } 

Sie können auch bool b = std::ifstream('filename').good(); . Ohne die Verzweigungsbefehle (wie wenn) muss es schneller arbeiten, da es tausende Male aufgerufen werden muss.

Wenn Sie zwischen einer Datei und einem Verzeichnis unterscheiden müssen, sollten Sie folgendes beachten: Beide verwenden stat als das schnellste Standard-Tool, wie von PherricOxid gezeigt:

 #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); }) 

Wobei R deine Abfolge von wegähnlichen Dingen ist und exists() von der zukünftigen std oder aktuellen Boost ist. Wenn Sie Ihre eigenen rollen, halten Sie es einfach,

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

Die verzweigte Lösung ist nicht absolut schrecklich und wird keine Dateideskriptoren verschlingen,

 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 } 

Sie können std::ifstream , funcion wie is_open , fail , zum Beispiel wie unten beschrieben (der cout “open” bedeutet Datei existiert oder nicht):

Bildbeschreibung hier eingeben

Bildbeschreibung hier eingeben

zitiert aus dieser Antwort

Mit MFC ist es möglich, mit den folgenden

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

Wobei FileName eine Zeichenkette ist, die die Datei darstellt, nach der Sie suchen

Ich brauche eine schnelle function, die prüfen kann, ob eine Datei existiert oder nicht, und PherricOxids Antwort ist fast das, was ich brauche, außer dass sie nicht die performance von boost :: filesystem :: exists und offenen functionen vergleicht. Aus den Benchmark-Ergebnissen können wir leicht sehen, dass:

  • Die Verwendung der Statistikfunktion ist der schnellste Weg, um zu überprüfen, ob eine Datei existiert. Beachten Sie, dass meine Ergebnisse mit der Antwort von PherricOxid übereinstimmen.

  • Die performance der function boost :: filesystem :: exists ist der function stat sehr ähnlich und sie ist auch portabel. Ich würde diese Lösung empfehlen, wenn Boost-Bibliotheken über Ihren Code zugänglich sind.

Benchmark-Ergebnisse mit dem Linux-coreel 4.17.0 und 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 

Unten ist mein Benchmark-Code:

 #include  #include  #include  #include  #include  #include  #include  #include  #include "boost/filesystem.hpp" #include  const std::string 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(); 

In C ++ 17:

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

Obwohl es mehrere Möglichkeiten gibt, dies zu tun, wäre die effizienteste Lösung für Ihr Problem wahrscheinlich eine der vordefinierten Methoden von fstream wie good () . Mit dieser Methode können Sie prüfen, ob die von Ihnen angegebene Datei existiert oder nicht.

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

Ich hoffe, Sie finden das nützlich.