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


453

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

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

2
boost::filesystem使用しているようstat()です。(ドキュメントから推測します。)FS呼び出しの方がはるかに速くできるとは思いません。作業を高速化する方法は、「何千ものファイルを見ないようにする」ことです。
12

16
TOCTOUの質問:ファイルがexists()チェックと「何かを実行中」の間でリンク解除されていないことをどのようにして確認しますか?
ピルクロー

7
@pilcrow良い点ですが、それほど多くの正確さを必要としないかなり広い範囲のアプリケーションがあります。たとえばgit push、最初のダーティチェックの後で作業ツリーに触れていないことを確認する必要はありません。
ミリムース

9
「それがないC / C ++実装を考えることはできません」-WindowsはPOSIX環境を提供していません。
ジムバルター、2012年

回答:


778

さて、これらのメソッドをそれぞれ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); 
}

5回の実行で平均した100,000回の呼び出しを実行する合計時間の結果、

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関数の使用を拒否した場合は、標準の呼び出しが最善の策です。


31
上記のメソッドはいずれも存在をチェックせず、アクセシビリティをチェックします。しかし、存在を確認するための単一の標準CまたはC ++の方法を知りません。
IInspectable 2013

10
stat()存在を確認しているようです。
el.pescado 2013年

105
これを使用する人は、#include <sys / stat.h>を覚えておく必要があります。そうしないと、間違った統計を使用しようとします。
Katianie 2014

23
ifstreamメソッドの場合f.close()、fが関数の最後でスコープ外になるため、必要はないと思います。それでreturn f.good()ifブロックを交換できますか?
ilent2 14

11
次の標準のen.cppreference.com/w/cpp/experimental/fs/existsを使用/テストすることもできます
zahir

153

備考:C ++ 14では、ファイルシステムTSが完成して採用されるとすぐに、解決策は次のものを使用することです。

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

C ++ 17以降、次の場合のみ:

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


1
MS Visual Studio 2013では、この機能はstd::tr2::sys::exists("helloworld.txt");
Constantin

3
私は実際にそれがそうでないことを望みますstd::exists、それはかなり混乱するでしょう(考えてください:セットのようなSTLコンテナに存在します)。
einpoklum 2016

3
また、Visual Studio 2015:#include <experimental/filesystem> bool file_exists(std::string fn) { std::experimental::filesystem::exists("helloworld.txt"); }
Orwellophile 2017

1
忘れずに#include <experimental/filesystem>
Mohammed Noureldin

112

私はこのコードを使用していますが、これまでのところ問題なく動作します。これは、C ++の多くの凝った機能を使用していません。

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

8
ただし、ファイルが別のプログラムによってロックされている場合、またはファイルにアクセスできない場合は、失敗する可能性があります。
Jet

2
ストリームを閉じる必要がありますか?
Mo0gles 2015年

29
@ Mo0gles:ifstreamデストラクタは終了時に呼び出されis_file_exist、ストリームを閉じます。
アイザック

2
C ++ 11以降では、ブール演算子を使用して1行でそれを行うことができます:en.cppreference.com/w/cpp/io/basic_ios/operator_bool
Mugen

6
@Orwellophilereturn std::ifstream(fileName);
emlai

27

ファイルがどこにあるかによります。たとえば、それらがすべて同じディレクトリにあると想定されている場合、すべてのディレクトリエントリをハッシュテーブルに読み込んでから、すべての名前をハッシュテーブルと照合できます。これは可能性が速く、いくつかのシステム上の各ファイルを個別にチェックするよりも。各ファイルを個別にチェックする最速の方法はシステムに依存します... ANSI Cを作成している場合fopen、それが唯一の方法であるため、最速の方法はそれです(ファイルは存在するが開いていない可能性がありますが、 「それに何かをする必要がある」)。C ++、POSIX、Windowsはすべて追加オプションを提供します。

その間、質問の問題をいくつか指摘させてください。あなたは最速の方法を望んでおり、何千ものファイルがあると言いますが、単一のファイルをテストするための関数のコードを要求します(そしてその関数はCではなくC ++でのみ有効です)。これは、ソリューションについての仮定、つまりXY問題のケースを作成することによって、要件と矛盾します。また、「標準のc ++ 11(or)c ++(or)cで」と言います...これはすべて異なり、これも速度の要件と一致しません...最速の解決策は、コードをターゲットシステム。質問の不整合は、システムに依存し、標準のCまたはC ++ではないソリューションを提供する回答を受け入れたという事実によって強調されます。


25

ブーストが好きな人のために:

 boost::filesystem::exists(fileName)

5
ブーストは通常​​非常に遅いです。
セルジュロガッチ2016

4
ほとんどのアプリケーションでは、ファイルが存在するかどうかの確認はパフォーマンスにとって重要ではありません
anhoppe

29
高性能アプリケーションのすべての側面に最適化が必要なわけではありません。たとえば、アプリケーション自体はC ++のパフォーマンス上の利点を必要とする場合がありますが、コマンドラインまたは構成ファイルの読み取りは複雑で速度を必要としない場合があります。このような場合にBoostを回避することは、アンチパターンリストの上位にあるホイールの再発明を構成します。
evoskuil 2016年

5
@SergeRogatch boost :: filesystem :: existsが極端に遅くなることはありません。詳細については、ベンチマーク結果を参照してください。
hungptit

3
「Boostは通常非常に遅い」-これは誤りであり、主張の範囲が何であるかさえも明確ではありません... Boostには、さまざまな作者による多くのパッケージが含まれていますが、高品質が求められています。「ほとんどのアプリケーションでは、ファイルが存在するかどうかのチェックはパフォーマンスにとって重要ではありません」-非常に多数のファイルをチェックするため、OPは特に速度を求めました。「パフォーマンスが重要でなければ、C ++を使用しても意味がありません」-別の誤ったコメント(およびトピック外)。ほとんどのソフトウェアはショップで作成され、言語の選択を義務付けるシステムの一部です。
ジムBalter

23

他のライブラリを使用せずに、次のコードスニペットを使用したいと思います。

#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準拠システムのクロスプラットフォームで機能します。


これはMacで動作しますか?Macを持っていませんが、Macにunistd.hも含めることができると思います。たぶん、最初のもの#ifdefはウィンドウ固有のものでなければなりませんか?
16

5
Mac OSXはPOSIXに準拠しています。
schaiba

20

PherricOxideによって提案されたのと同じですが、C

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

1
.c_str()はC ++関数です。C ++を知らないので、Cの同等物を投稿しました。
Ramon La Pietra 14

10
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.
}

19
本当にそうするつもりなら、if / elseブランチを使用するのではなく、単に「(bool)ファイルを返す」だけです。
Nik Haldimann、

本当の場合はファイルを閉じることを忘れないでください。これは、プログラムのランタイム全体にわたってファイルを開いたままにした場合の一種のメモリリークです。言うまでもなく、ファイルがロックされているため、ファイルが存在することを知ってから読み取ることができません。add:file.close()他の2番目に。
ビル・ムーア

2
考え直して、おそらくそれを明示的に閉じる必要はないかもしれません... ifstreamがRAII(Resource Acquisition Is Initialization)であることを忘れてしまいました...そして、デストラクタからスコープから外れると自動的にクリーンアップします...何私が言うことができる...私はこれらの日ガベージコレクタ言語によって洗脳を取得...
ビル・ムーア

@BillMoore 2番目のコメントは正しいです。このページの他の多くのコメントclose()は不要であると述べています。
キースM

これは存在ではなくアクセス可能性をチェックします。たとえば、ファイルは存在するが、アクセス権のためにアクセスできない場合、falseを返し、誤ってファイルが存在しないと主張します。
SasQ

7

ウィンドウの下の別の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;
}

inline bool exist(const std::string& name)
{
    return GetFileAttributes(name.c_str()) != INVALID_FILE_ATTRIBUTES;
}


5
GetFileAttributesバージョンは基本的にWindowsでそれを行うための標準的な方法です。
Felix Dombek 2015年

私はこれが古いことを知っていますが、ユーザーがファイルを読み取ることができてもファイル属性の読み取りが許可されていない場合、3番目のケースではどうなりますか?
クエスト

6

あなたもするかもしれませんbool b = std::ifstream('filename').good();。分岐命令がない場合(ifのような)、何千回も呼び出す必要があるため、より高速に実行する必要があります。


受け入れられた答えが示すように、これは真実ではありません。深刻なコンパイラーは、ifを使用するかどうかに関係なく、おそらく同じコードを出力します。プレーンCのバリアントと比較して、ifstreamオブジェクトを(スタック上にある場合でも)構築すると、追加のオーバーヘッドが発生します。
minexew 2016

5

ファイルとディレクトリを区別する必要がある場合は、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

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

  • stat関数の使用は、ファイルが存在するかどうかを確認する最も速い方法です。私の結果はPherricOxideの答えと一致していることに注意してください。

  • boost :: filesystem :: exists関数のパフォーマンスは、stat関数のパフォーマンスに非常に近く、移植性もあります。コードからboostライブラリにアクセスできる場合は、このソリューションをお勧めします。

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

4

あなたは使用することができstd::ifstream、同様funcionをis_openfail:コード(coutの「オープン」とは、ファイルの存在するかしない)以下のように、たとえば、

ここに画像の説明を入力してください

ここに画像の説明を入力してください

この回答から引用


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

PathFileExistsMAX_PATH(260)文字に制限されています。GetFileAttributesこの制限はありません。
Felix Dombek

GetFileAttributesMAX_PATHにも制限されます。ドキュメントでは、絶対パス、Unicodeを使用し、パス名の前に特別なプレフィックス文字列を付加する場合の回避策について説明しています。いずれにせよ、Windows固有の対応に取り掛かっていると思います。
ジョン、

1
GetFileAttributesW制限はありません。
Laurie Stearn

1

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

5
これは、4年前のVincentの回答よりも有益ではありません。
ジムBalter

2
C ++ 17では、ファイルシステムは実験的ではなくなりました
Quest

0

MFCを使用すると、次のことが可能になります。

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

FileName存在を確認するファイルを表す文字列はどこですか


0

ファイルが存在するかどうかを確認する高速な方法は1つだけです。それを読み取る権限がある場合は、C言語の願いを使用する方が高速で、C ++のどのバージョンでも使用できます

解決策:Cには、エラーのタイプを認識するために使用できる番号を含むerrnoと呼ばれる外部(グローバル)整数変数を持つライブラリerrno.hがあります。

    #include <stdio.h>
    #include <stdbool.h>
    #include <errno.h>

    bool isFileExist(char fileName[]) {
        FILE *fp = fopen(fileName, "r");
        if (fp) {
            fclose(fp);
            return true;
        }
        return errno != ENOENT;
    }

    bool isFileCanBeRead(char fileName[]) {
        FILE *fp = fopen(fileName, "r");
        if (fp) {
            fclose(fp);
            return true;
        }
        return errno != ENOENT && errno != EPERM;
    }

-4

これを行うにはいくつかの方法がありますが、問題に対する最も効率的な解決策は、おそらくgood()などのfstreamの定義済みメソッドの1つを使用することです。この方法を使用すると、指定したファイルが存在するかどうかを確認できます。

fstream file("file_name.txt");

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

これがお役に立てば幸いです。


4
このコードはファイルが存在しない場合に作成するため、結果は常にtrueになります。ifstreamを使用するか、openmodeパラメータを正しく設定する必要があります。
Lubo Antonov
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.