web-dev-qa-db-ja.com

標準のC++/C++ 11/Cを使用してファイルが存在するかどうかを確認する最速の方法は?

ファイルが標準のC++ 11、C++、またはCに存在するかどうかを確認する最も早い方法を見つけたいと思います。次の関数で/* SOMETHING */の代わりに何を書くことができますか?

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

それで、私はこれらの方法のそれぞれを10万回実行するテストプログラムをまとめました。半分は存在するファイルと半分は存在しないファイルです。

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

10回のコールを実行するための合計時間の結果は、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++でコンパイルされたもの)で最高のパフォーマンスを提供し、何らかの理由でPOSIX関数の使用を拒否した場合は標準のfopen呼び出しが最善の策です。

653
PherricOxide

注意:C++ 14では、 ファイルシステムTS が完成し採用されるとすぐに、解決策は次のようになります。

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

そしてC++ 17以降、ただ:

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

私はこのコードを使用します、これまでのところ私には問題なく動作します。これはC++の多くの派手な機能を使用しません。

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

ファイルが存在する場所によって異なります。たとえば、それらがすべて同じディレクトリにあると想定される場合は、すべてのディレクトリエントリをハッシュテーブルに読み込んでから、ハッシュテーブルに対してすべての名前を確認できます。この たぶん いくつかのシステムでは各ファイルを個別にチェックするより速いでしょう。それぞれのファイルを個別にチェックする最も早い方法はあなたのシステムに依存します…ANSI Cを書いているなら、最速の方法はfopenです。あなたは「その上で何かをする」必要があります。 C++、POSIX、Windowsはすべて追加オプションを提供します。

私がそれにたどり着いている間、あなたの質問に関するいくつかの問題を指摘させてください。あなたはあなたが最も速い方法が欲しい、そしてあなたがあなたが何千ものファイルを持っていると言うけれども、それからあなたは一つのファイルをテストするための関数のためのコードを求めるこれは解について仮定をすることによってあなたの要求と矛盾します... 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準拠のシステムのためのクロスプラットフォームで動作します。

17
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

ファイルとディレクトリを区別する必要がある場合は、PherricOxideによって実証されているように、どちらも最も速い標準的なツールであるstatを使用する次の点を考慮してください。

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

ファイルが存在するかどうかをチェックできる高速な関数が必要です。PherricOxideの答えは、boost :: filesystem :: existsとopen関数のパフォーマンスを比較しないことを除けば、ほとんど私が必要とするものです。ベンチマーク結果から、次のことが簡単にわかります。

  • 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();   
2
hungptit

例えば、以下のコードのように、std::ifstreamis_openfailのような関数を使用することができます(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