Najszybszy sposób sprawdzenia, czy plik istnieje przy użyciu standardowego C++/C++11 / C?

Chciałbym znaleźć najszybszy sposób, aby sprawdzić, czy plik istnieje w standardowym C++11, C++, lub C. mam tysiące plików i zanim coś na nich zrobię, muszę sprawdzić, czy wszystkie z nich istnieją. Co mogę napisać zamiast /* SOMETHING */ w poniższej funkcji?

inline bool exist(const std::string& name)
{
    /* SOMETHING */
}
 326
Author: MD XF, 2012-10-08

17 answers

Cóż, rzuciłem razem program testowy, który uruchomił każdą z tych metod 100,000 razy, w połowie na plikach, które istniały, a w połowie na plikach, które nie.

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

Wyniki dla łącznego czasu uruchomienia 100 000 połączeń uśrednionych w 5 biegach,

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

Funkcja stat() zapewniała najlepszą wydajność w moim systemie (Linux, skompilowana z g++), A standardowe wywołanie fopen było najlepszym rozwiązaniem, jeśli z jakiegoś powodu odmówisz korzystania z funkcji POSIX.

 582
Author: PherricOxide,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-05 11:31:18

Używam tego kawałka kodu, jak na razie Działa OK. To nie używa wielu fantazyjnych funkcji C++:

bool is_file_exist(const char *fileName)
{
    std::ifstream infile(fileName);
    return infile.good();
}
 83
Author: harryngh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-07 16:45:31

Uwaga: W C++14 i jak tylko system plików TS zostanie ukończony i przyjęty, rozwiązaniem będzie użycie:

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

A od C++17 tylko:

std::filesystem::exists("helloworld.txt");
 79
Author: Vincent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-16 23:50:31

To zależy od tego, gdzie znajdują się pliki. Na przykład, jeśli wszystkie powinny znajdować się w tym samym katalogu, możesz odczytać wszystkie wpisy katalogu w tabeli hash, a następnie sprawdzić wszystkie nazwy w tabeli hash. To Może być szybsze na niektórych systemach niż sprawdzanie KAŻDEGO pliku osobno. Najszybszy sposób sprawdzenia KAŻDEGO pliku indywidualnie zależy od systemu ... jeśli piszesz ANSI C, najszybszym sposobem jest fopen, ponieważ jest to jedyny sposób (plik może istnieć, ale nie być openable, ale prawdopodobnie naprawdę chcesz openable, jeśli chcesz "coś na nim zrobić"). C++, POSIX, Windows wszystkie oferują dodatkowe opcje.

Skoro już o tym mowa, pozwól, że zwrócę uwagę na kilka problemów z twoim pytaniem. Mówisz, że chcesz najszybszą drogę i że masz tysiące plików, ale potem prosisz o kod funkcji do testowania pojedynczego pliku(i ta funkcja jest ważna tylko w C++, a nie C). Jest to sprzeczne z Twoimi wymaganiami, przyjmując założenie dotyczące rozwiązania ... sprawa z problemu XY . Można również powiedzieć "w standardowym c++11 (or)c++(or)c"... które są różne, a to również jest niezgodne z Twoim wymogiem prędkości ... najszybsze rozwiązanie polegałoby na dopasowaniu kodu do systemu docelowego. Niespójność w pytaniu podkreśla fakt, że zaakceptowałeś odpowiedź, która daje rozwiązania, które są zależne od systemu i nie są standardem C lub c++.
 25
Author: Jim Balter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-20 10:29:30

Dla tych, którzy lubią boost:

 boost::filesystem::exists(fileName)
 21
Author: anhoppe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-21 08:30:10

Bez używania innych bibliotek, lubię używać poniższego fragmentu kodu:

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

To działa międzyplatformowo dla Systemów Windows i zgodnych z POSIX.

 17
Author: Viktor Liehr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-05 04:07:48

To samo, co sugeruje PherricOxide, ale w C

#include <sys/stat.h>
int exist(const char *name)
{
  struct stat   buffer;
  return (stat (name, &buffer) == 0);
}
 14
Author: Ramon La Pietra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-28 03:32:33
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.
}
 9
Author: LOLOLOL,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-08 15:54:45

Kolejne 3 opcje pod 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;
}
 6
Author: ravin.wang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-22 15:18:18

Możesz również zrobić bool b = std::ifstream('filename').good();. Bez instrukcji gałęzi(jak if) musi działać szybciej, ponieważ musi być wywoływana tysiące razy.

 4
Author: parv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-25 05:48:35

Jeśli chcesz odróżnić Plik od katalogu, rozważ następujące, które oba używają stat, które jest najszybszym standardowym narzędziem, jak pokazano w PherricOxide:

#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;
}
 4
Author: user3902302,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-21 13:30:22
all_of (begin(R), end(R), [](auto&p){ exists(p); })

Gdzie R jest Twoim ciągiem rzeczy podobnych do ścieżki, a {[4] } jest z przyszłego std lub obecnego boost. Jeśli kręcisz własnym, trzymaj to prosto,

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

Rozwiązanie rozgałęzione nie jest absolutnie straszne i nie pożera deskryptorów plików,

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
Author: John,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-25 00:57:03

Potrzebuję szybkiej funkcji, która może sprawdzić, czy plik istnieje czy nie i odpowiedź PherricOxide jest prawie taka, jakiej potrzebuję, z wyjątkiem tego, że nie porównuje wydajności boost::filesystem::exists i funkcji open. Z wyników benchmarku możemy łatwo zauważyć, że:

  • Korzystanie z funkcji stat jest najszybszym sposobem sprawdzenia, czy plik istnieje. Zauważ, że moje wyniki są zgodne z odpowiedzią PherricOxide.

  • Wydajność funkcji boost:: filesystem:: exists jest bardzo zbliżony do funkcji stat i jest również przenośny. Polecam to rozwiązanie, jeśli biblioteki boost są dostępne z twojego kodu.

Wyniki porównawcze uzyskane z jądrem Linuksa 4.17.0 i 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

Poniżej znajduje się mój kod odniesienia:

#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();   
 1
Author: hungptit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-05 04:51:34

Możesz użyć std::ifstream, funcion jak is_open, fail, na przykład jak poniżej (cout "open" oznacza, że plik istnieje lub nie):

Tutaj wpisz opis obrazka

Tutaj wpisz opis obrazka

Cytowane z tego odpowiedź

 1
Author: Jayhello,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-12 08:59:55

Korzystanie z MFC jest możliwe za pomocą następujących

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

Gdzie {[1] } jest łańcuchem znaków reprezentującym plik, który sprawdzasz pod kątem istnienia

 0
Author: Andy Bantly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-28 03:32:38

W C++17:

#include <experimental/filesystem>

bool is_file_exist(std::string& str) {   
    namespace fs = std::experimental::filesystem;
    fs::path p(str);
    return fs::exists(p);
}
 0
Author: Abhijeet Kandalkar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-28 16:25:59

Chociaż istnieje kilka sposobów, aby to zrobić, najskuteczniejszym rozwiązaniem problemu byłoby prawdopodobnie użycie jednej z predefiniowanych metod fstream, takich jak good () . Za pomocą tej metody możesz sprawdzić, czy podany plik istnieje, czy nie.

fstream file("file_name.txt");

if (file.good()) 
{
    std::cout << "file is good." << endl;
}
else 
{
    std::cout << "file isnt good" << endl;
}
Mam nadzieję, że to ci się przyda.
 -2
Author: miksiii,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-17 21:19:28