it-roy-ru.com

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

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

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

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

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

Результаты общего времени для выполнения 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.

662
PherricOxide

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

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

и начиная с C++ 17 только:

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

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

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

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

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

26
Jim Balter

Для тех, кто любит повышение:

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

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

#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-совместимых систем.

19
Viktor Liehr

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

#include <sys/stat.h>
int exist(const char *name)
{
  struct stat   buffer;
  return (stat (name, &buffer) == 0);
}
15
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

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

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

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

4
parv

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

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

  • Производительность функции boost :: filesystem :: exist очень близка к производительности функции 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();   
3
hungptit
all_of (begin(R), end(R), [](auto&p){ exists(p); })

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

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

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

enter image description here

enter image description here

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

2
Jayhello

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

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

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

0
Andy Bantly