it-swarm.com.de

Der schnellste Weg, um zu überprüfen, ob eine Datei mit Standard-C ++ / C ++ 11 / C vorhanden ist?

Ich möchte den schnellsten Weg finden, um zu überprüfen, ob eine Datei in Standard-C++ 11, C++ oder C vorhanden ist. Ich habe Tausende von Dateien, und bevor ich etwas auf ihnen tun kann, muss ich überprüfen, ob alle vorhanden sind. Was kann ich in der folgenden Funktion anstelle von /* SOMETHING */ schreiben?

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

Nun, ich habe ein Testprogramm zusammengestellt, mit dem jede dieser Methoden 100.000 Mal ausgeführt wurde, je zur Hälfte für existierende und nicht existierende Dateien.

#include <sys/stat.h>
#include <unistd.h>
#include <string>
#include <fstream>

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 Gesamtlaufzeit 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 Funktion stat() lieferte die beste Leistung auf meinem System (Linux, kompiliert mit g++), wobei ein Standardaufruf fopen Ihre beste Wahl ist, wenn Sie aus irgendeinem Grund die Verwendung von POSIX-Funktionen verweigern.

679
PherricOxide

Bemerkung: In C++ 14 und sobald das Dateisystem TS fertiggestellt und übernommen ist, lautet die Lösung:

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

und seit C++ 17 nur:

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

Ich benutze diesen Code, es funktioniert soweit bei mir OK. Dies nutzt nicht viele ausgefallene Funktionen von C++:

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

Es hängt davon ab, wo sich die Dateien befinden. Wenn sich beispielsweise alle im selben Verzeichnis befinden sollen, können Sie alle Verzeichniseinträge in eine Hash-Tabelle einlesen und dann alle Namen mit der Hash-Tabelle abgleichen. Diese könnte Seien Sie auf manchen Systemen schneller, als wenn Sie jede Datei einzeln prüfen. Der schnellste Weg, um jede Datei einzeln zu prüfen, hängt von Ihrem System ab. Wenn Sie ANSI C schreiben, ist der schnellste Weg fopen, da dies der einzige Weg ist (eine Datei existiert möglicherweise, kann aber nicht geöffnet werden, aber Sie wahrscheinlich) wirklich öffenbar wollen, wenn man "etwas drauf machen" muss). C++, POSIX und Windows bieten zusätzliche Optionen.

Lassen Sie mich auf einige Probleme bei Ihrer Frage hinweisen. Sie sagen, dass Sie den schnellsten Weg wollen und dass Sie Tausende von Dateien haben, fragen dann aber nach dem Code für eine Funktion, um eine einzelne Datei zu testen (und diese Funktion ist nur in C++ gültig, nicht in C). Dies widerspricht Ihren Anforderungen, indem Sie eine Annahme über die Lösung treffen ... ein Fall von das XY-Problem . Sie sagen auch "in standard c ++ 11 (oder) c ++ (oder) c", die alle unterschiedlich sind, und dies steht auch nicht im Einklang mit Ihren Anforderungen an die Geschwindigkeit ... Die schnellste Lösung wäre das Anpassen des Codes an die Zielsystem. Die Inkonsistenz in der Frage wird durch die Tatsache hervorgehoben, dass Sie eine Antwort akzeptiert haben, die systemabhängige Lösungen liefert, bei denen es sich nicht um Standard-C oder C++ handelt.

26
Jim Balter

Für diejenigen, die Boost mögen:

 boost::filesystem::exists(fileName)
22
anhoppe

Ohne andere Bibliotheken zu verwenden, verwende ich gerne den folgenden Codeausschnitt:

#ifdef _WIN32
   #include <io.h> 
   #define access    _access_s
#else
   #include <unistd.h>
#endif

bool FileExists( const std::string &Filename )
{
    return access( Filename.c_str(), 0 ) == 0;
}

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

19
Viktor Liehr

Wie von PherricOxide vorgeschlagen, jedoch in C

#include <sys/stat.h>
int exist(const char *name)
{
  struct stat   buffer;
  return (stat (name, &buffer) == 0);
}
17
Ramon La Pietra
inline bool exist(const std::string& name)
{
    ifstream file(name);
    if(!file)            // If the file was not found, then file is 0, i.e. !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.
}
10
LOLOLOL

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;
}
7
ravin.wang

Wenn Sie zwischen einer Datei und einem Verzeichnis unterscheiden müssen, beachten Sie Folgendes, wobei beide stat verwenden, welches das schnellste Standardwerkzeug ist, wie PherricOxide demonstriert:

#include <sys/stat.h>
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;
}
5
user3902302

Sie können auch bool b = std::ifstream('filename').good(); ausführen. Ohne die Verzweigungsanweisungen (wie if) muss es schneller ausgeführt werden, da es Tausende Male aufgerufen werden muss.

4
parv

Ich brauche eine schnelle Funktion, die prüfen kann, ob eine Datei existiert oder nicht, und die Antwort von PherricOxide ist fast das, was ich brauche, außer dass sie nicht die Leistung von boost :: filesystem :: exists- und open-Funktionen vergleicht. An den Benchmark-Ergebnissen können wir leicht erkennen, dass:

  • Mit der stat-Funktion können Sie am schnellsten überprüfen, ob eine Datei vorhanden ist. Beachten Sie, dass meine Ergebnisse mit denen von PherricOxide übereinstimmen.

  • Die Leistung der Funktion boost :: filesystem :: exists ist der der Funktion stat sehr ähnlich und kann auch portiert werden. Ich würde diese Lösung empfehlen, wenn Sie von Ihrem Code aus auf Boost-Bibliotheken zugreifen können.

Benchmark-Ergebnisse mit Linux-Kernel 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 <string.h>                                                                                                                                                                                                                                           
#include <stdlib.h>                                                                                                                                                                                                                                           
#include <sys/types.h>                                                                                                                                                                                                                                        
#include <sys/stat.h>                                                                                                                                                                                                                                         
#include <unistd.h>                                                                                                                                                                                                                                           
#include <dirent.h>                                                                                                                                                                                                                                           
#include <fcntl.h>                                                                                                                                                                                                                                            
#include <unistd.h>                                                                                                                                                                                                                                           

#include "boost/filesystem.hpp"                                                                                                                                                                                                                               

#include <benchmark/benchmark.h>                                                                                                                                                                                                                              

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();   
3
hungptit
all_of (begin(R), end(R), [](auto&p){ exists(p); })

wobei R Ihre Abfolge von pfadähnlichen Dingen ist und exists() aus dem zukünftigen Standard oder aktuellen Boost stammt. 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 verschlingt keine Dateideskriptoren.

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
}
3
John

Sie können std::ifstream verwenden, Funktionen wie is_open, fail, zum Beispiel wie folgt:

enter image description here

enter image description here

zitiert von diesem Antwort

3
Jayhello

Das Verwenden von MFC ist mit folgend möglich

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

Wobei FileName eine Zeichenfolge ist, die die zu überprüfende Datei darstellt

0
Andy Bantly