Самый быстрый способ проверить, существует ли файл с использованием стандартного С++/С++ 11/C?

Я хотел бы найти самый быстрый способ проверить, существует ли файл в стандартном С++ 11, С++ или C. У меня есть тысячи файлов и перед тем, как что-то делать с ними, мне нужно проверить, все ли они существуют. Что я могу написать вместо /* SOMETHING */ в следующей функции?

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

Ответ 1

Хорошо, я бросил вместе тестовую программу, которая запускала каждый из этих методов 100 000 раз, наполовину на файлы, которые существовали, и половина на файлы, которые этого не сделали.

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

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

Результаты за общее время для запуска 100 000 звонков, усредненных за 5 прогонов,

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

Функция stat() обеспечивала лучшую производительность в моей системе (Linux, скомпилированная с помощью g++), при этом стандартный вызов fopen является лучшим выбором, если вы по какой-то причине отказываетесь от использования функций POSIX.

Ответ 2

Я использую этот кусок кода, он работает со мной до сих пор. Это не использует многие причудливые функции С++:

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

Ответ 3

Замечание: в С++ 14 и как только файловая система TS будет завершена и принята, решение будет использовать:

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

и поскольку С++ 17, только:

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

Ответ 4

Это зависит от того, где находятся файлы. Например, если все они должны находиться в одном каталоге, вы можете прочитать все записи каталога в хэш-таблицу, а затем проверить все имена на хэш-таблицу. Этот может быть быстрее на некоторых системах, чем проверять каждый файл по отдельности. Самый быстрый способ проверить каждый файл в отдельности зависит от вашей системы... если вы пишете ANSI C, самый быстрый способ - fopen, потому что это единственный способ (файл может существовать, но не быть открытым, но вы, вероятно, действительно хотите открыто, если вам нужно "что-то сделать" ). С++, POSIX, Windows предлагают дополнительные опции.

Пока я нахожусь на этом, позвольте мне указать на некоторые проблемы с вашим вопросом. Вы говорите, что хотите самый быстрый способ, и что у вас есть тысячи файлов, но затем вы просите код для функции протестировать один файл (и эта функция действительна только на С++, а не на C). Это противоречит вашим требованиям, сделав предположение о решении... случай проблемы XY. Вы также говорите "в стандартном С++ 11 (или) С++ (или) c"..., которые все разные, и это также не соответствует вашему требованию скорости... самое быстрое решение будет заключаться в адаптации кода к целевой системы. Непоследовательность в вопросе подчеркивается тем фактом, что вы приняли ответ, который дает решения, зависящие от системы, и не являются стандартными C или С++.

Ответ 5

Для тех, кому нравится boost:

 boost::filesystem::exists(fileName)

Ответ 6

Без использования других библиотек мне нравится использовать следующий фрагмент кода:

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

Это работает кросс-платформенная для Windows и POSIX-совместимых систем.

Ответ 7

То же, что предложено PherricOxide, но в C

#include <sys/stat.h>
int exist(const char *name)
{
  struct stat   buffer;
  return (stat (name, &buffer) == 0);
}

Ответ 8

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

Еще 3 варианта под окнами:

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

Ответ 10

Вы также можете сделать bool b = std::ifstream('filename').good();. Без инструкций ветвления (например, если) он должен выполняться быстрее, поскольку его нужно называть тысячами раз.

Ответ 11

Если вам нужно провести различие между файлом и каталогом, рассмотрите следующее, которое использует stat, который является самым быстрым стандартным инструментом, как показано 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;
}

Ответ 12

all_of (begin(R), end(R), [](auto&p){ exists(p); })

где R - это ваша последовательность дорожных вещей, а exists() - из будущего std или текущего повышения. Если вы откажетесь от своего собственного, держите его простым,

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

Разветвленное решение не является абсолютно ужасным и не будет уничтожать дескрипторы файлов,

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
}

Ответ 13

Вы можете использовать std::ifstream, std::ifstream, например is_open, fail, например, как ниже код (cout "open" означает, что файл существует или нет):

enter image description here

enter image description here

цитируется из этого ответа

Ответ 14

Использование MFC возможно со следующим

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

Где FileName - это строка, представляющая файл, который вы проверяете на наличие

Ответ 15

Мне нужна быстрая функция, которая может проверить, существует ли файл или нет, а ответ PherricOxide - это почти то, что мне нужно, кроме того, что он не сравнивает производительность boost :: filesystem :: существует и открывает функции. Из результатов теста мы легко видим, что:

  • Использование функции stat - это самый быстрый способ проверить, существует ли файл. Обратите внимание, что мои результаты согласуются с результатами ответа PherricOxide.

  • Производительность функции boost :: filesystem :: exists очень близка к функции stat, и она также переносима. Я бы рекомендовал это решение, если из вашего кода доступны более мощные библиотеки.

Результаты тестов, полученные с ядром Linux 4.17.0 и 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

Ниже приведен мой контрольный код:

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

Ответ 16

В С++ 17:

#include <experimental/filesystem>

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

Ответ 17

Хотя существует несколько способов сделать это, наиболее эффективным решением вашей проблемы, вероятно, будет использование одного из предопределенных методов fstream, например good(). С помощью этого метода вы можете проверить, существует ли указанный вами файл.

fstream file("file_name.txt");

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

Надеюсь, вы сочтете это полезным.