563

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

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

23 に答える 23

928

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

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

方法 時間
exists_test0(ifstream) 0.485秒
exists_test1(ファイルfopen) 0.302秒
exists_test2(posix access()) 0.202秒
exists_test3(posix stat()) 0.134秒

このstat()関数は、私のシステム(Linux、でコンパイルされたg++)で最高のパフォーマンスを提供し、何らかの理由でPOSIX関数の使用を拒否した場合は、標準のfopen呼び出しが最善の策です。

于 2012-10-08T01:43:22.110 に答える
213

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

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

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

std::filesystem::exists("helloworld.txt");
于 2014-07-15T05:01:19.407 に答える
128

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

bool is_file_exist(const char *fileName)
{
    std::ifstream infile(fileName);
    return infile.good();
}
于 2013-11-07T16:45:31.030 に答える
33

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

 boost::filesystem::exists(fileName)

または、ISO C ++ 17以降:

 std::filesystem::exists(fileName)
于 2015-09-21T08:30:10.093 に答える
29

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

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

于 2012-10-08T01:35:33.347 に答える
28

他のライブラリを使用せずに、次のコードスニペットを使用するのが好きです。

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

于 2015-11-02T20:15:42.640 に答える
23

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

#include <sys/stat.h>
int exist(const char *name)
{
  struct stat   buffer;
  return (stat (name, &buffer) == 0);
}
于 2014-03-12T09:56:29.177 に答える
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.
}
于 2014-02-05T21:39:52.587 に答える
8

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

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

  • boost :: filesystem :: exits関数のパフォーマンスは、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();   
于 2018-05-05T04:51:34.277 に答える
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;
}

3

inline bool exist(const std::string& name)
{
    return GetFileAttributes(name.c_str()) != INVALID_FILE_ATTRIBUTES;
}
于 2014-08-22T15:18:18.970 に答える
6

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

于 2014-08-22T14:01:00.077 に答える
6

ファイルとディレクトリを区別する必要がある場合は、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;
}
于 2015-05-21T13:30:22.087 に答える
5

たとえば、次のコードのstd::ifstreamようis_openに、のような関数を使用できます(cout "open"は、ファイルが存在するかどうかを意味します)。fail

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

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

この回答から引用

于 2018-07-12T08:59:55.103 に答える
4

他のすべての回答は、すべてのファイルを個別にチェックすることに焦点を当てていますが、ファイルがすべて1つのディレクトリ(フォルダ)にある場合は、ディレクトリを読み取って、必要なすべてのファイル名の存在をチェックする方がはるかに効率的です。

これは、ファイルが複数のディレクトリに分散している場合でも、ディレクトリとファイルの正確な比率に応じて、さらに効率的になる可能性があります。独自のディレクトリにある各ターゲットファイルに近づき始めたら、または同じディレクトリにチェックしたくない他のファイルがたくさんあると、最終的には効率が低下することになります。各ファイルを個別にチェックするよりも。

優れたヒューリスティック:すでに持っている大量のデータを処理する方が、オペレーティングシステムに任意の量のデータを要求するよりもはるかに高速です。システムコールのオーバーヘッドは、個々のマシン命令に比べて非常に大きくなります。したがって、ほとんどの場合、OSに「このディレクトリ内のファイルのリスト全体を教えてください」と尋ねてからそのリストを調べ、OSに「このファイルに関する情報を教えてください」と尋ねる方が遅くなります。この他のファイルに関する情報を教えてください」、「...に関する情報を教えてください」など。

すべての優れたCライブラリは、バッファリングされたI / Oと同じように、効率的な方法で「ディレクトリ内のすべてのファイルを反復処理」APIを実装します。APIは次のように見えますが、内部的にはOSからディレクトリエントリの大きなリストを一度に読み取ります。 OSに各エントリを個別に要求します。


したがって、この要件がある場合は、

  1. すべてのファイルが1つのフォルダーにあり、他のファイルがそのフォルダーにないように、設計と使用法を促進するために可能な限りのことを行います。
  2. 存在する必要のあるファイル名のリストを、O(1)または少なくともO(log(n))のルックアップおよび削除時間(ハッシュマップやバイナリツリーなど)を持つメモリ内のデータ構造に配置します。
  3. そのディレクトリ内のファイルをリストし、メモリ内の「リスト」(ハッシュマップまたはバイナリツリー)から移動したときに、各ファイルを「チェックオフ」(削除)します。

正確なユースケースに依存する場合を除いて、ハッシュマップまたはツリーからエントリを削除する代わりに、「このファイルはありますか?」を追跡します。各エントリのブール値を計算し、O(1)が「すべてのファイルを持っていますか?」と尋ねるデータ構造を見つけます。おそらく二分木ですが、各非リーフノードの構造体にも論理的なブール値があります-そしてそのリーフノードのブール値です。これは適切にスケーリングされます。リーフノードにブール値を設定した後、ツリーを上って各ノードの「これを持っていますか?」を設定するだけです。子ノードのブール値を持つ&&ブール値(そして、他の子ノードを再帰的に実行する必要はありません。これは、リーフの1つをtrueに設定するたびにこのプロセスを一貫して実行している場合、それらは次のように設定されるためです。すべての子供がそうである場合にのみ真です。)


悲しいことに、C++17までそれを行う標準的な方法はありません。

C++17が取得しstd::filesystem::directory_iteratorました。

もちろんboost::filesystem::directory_iterator、C++の古いバージョンで動作すると私が推測する対応するものがあります。

標準のCウェイに最も近いのはopendirreaddirからdirent.hです。これは標準のCインターフェースであり、POSIXで標準化されているだけで、C標準自体では標準化されていません。Mac OS、Linux、すべてのBSD、その他のUNIX / UNIXライクなシステム、およびその他のPOSIX/SUSシステムですぐに使用できます。Windowsの場合、ダウンロードしてインクルードパスにドロップするだけのdirent.h実装があります。

ただし、最速の方法を探しているので、ポータブル/標準的なものを超えて見たいと思うかもしれません。

Linuxでは、rawシステムコールを使用してバッファサイズを手動で指定することにより、パフォーマンスを最適化できる場合がありますgetdents64

Windowsでは、少し掘り下げてみると、使用したい最大のパフォーマンスが得られるように見えますが、上記のWindows用のオープンソースライブラリの多くはそうではないようです。ただし、最後の2つのWindowsバージョンよりも古いバージョンで動作する必要があるコードの場合は、余分なフラグを付けずに単純なものを使用することもできます。FindFirstFileExFindExInfoBasicFIND_FIRST_EX_LARGE_FETCHdirent.hFindFirstFile

プラン9は上記のいずれにも含まれず、必要になりますdirreaddirreadallディレクトリの内容全体に十分なメモリがあると安全に想定できる場合は後者)。パフォーマンスのためにバッファサイズをより細かく制御したい場合は、プレーンを使用するreadread、ディレクトリエントリデータをデコードします。これらはドキュメント化されたマシンに依存しない形式であり、ヘルパー関数が提供されていると思います。

他のオペレーティングシステムについては知りません。


後でいくつかのテストでこの回答を編集する可能性があります。他の人も同様にテスト結果で編集することを歓迎します。

于 2020-09-24T17:36:13.293 に答える
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
}
于 2015-01-25T00:57:03.657 に答える
2

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);
}
于 2018-08-28T16:25:59.543 に答える
2

ファイルの存在をテストする最も速くて安全な方法は、ファイルを個別に/明示的にテストしないことです。つまり、通常のものを置き換える方法を見つけることができるかどうかを確認してください

if(exists(file)) {                           /* point A */
    /* handle existence condition */
    return;
}

do_something_with(file);                     /* point B */

改善された

r = do_something_with_unless_exists(file);

if(r == 0)
    success;
else if(errno == EEXIST)
    /* handle existence condition */
else
    /* handle other error */

これにより、高速になるだけでなく、最初のソリューションに固有の競合状態(具体的には、「TOC / TOU」)、つまり、ファイルがポイントAとポイントBの間に存在する可能性がなくなります。

明らかに、2番目の解決策は、操作を実行するためのアトミックな方法の存在を前提としていdo_something_with_unless_existsます。多くの場合、方法はありますが、場合によってはそれを探し回る必要があります。

  • open()ファイルの作成:とでO_CREAT呼び出しますO_EXCL

  • C11を使用している場合は、純粋なCでファイルを作成します。で呼び出しfopen()ます"wx"。(私は昨日これについて知ったばかりです。)

  • ディレクトリを作成する:後で電話mkdir()して確認するだけです。errno == EEXIST

  • ロックの取得:その塩に値するロックシステムには、すでにアトミックな取得-ロック-アズ-ロング-アズ-ノーバディ-エルス-ハズ-イットプリミティブがあります。

(他にもありますが、それらは私が今考えることができるものです。)

[脚注:Unixの初期には、ロックを実行するために通常のプロセスで利用できる特定の専用機能はありませんでした。したがって、ミューテックスを設定する場合、これは通常、mkdirsyscall以降、特定の空のディレクトリを作成することによって実装されていました。アトミックに、以前の存在または非存在に基づいて失敗または成功する能力を常に持っていました。]

于 2021-07-15T14:37:26.177 に答える
1

さらに簡単な方法があります

#include <fstream>
#include <iostream>

void FileExists(std::string myfile){
std::ifstream file(myfile.c_str());

if (file) {
    std::cout << "file exists" << std::endl;
}
else {
    std::cout << "file doesn't exist" << std::endl;
}
}

int main() {
FileExists("myfile.txt");

return 0;
}
于 2021-08-04T09:11:20.543 に答える
0

MFCを使用すると、次のようになります。

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

FileName存在を確認しているファイルを表す文字列はどこにありますか

于 2017-11-22T17:28:24.093 に答える
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;
    }
于 2020-03-30T05:44:58.010 に答える
0

これが簡単な例です!

#include <iostream>
#include <fstream>
using namespace std;
    
void main(){
   SearchFile("test.txt");
}

bool SearchFile(const char *file)
{
   ifstream infile(file);
   if (!infile.good())
   {
    // If file is not there
    exit(1);
   }
}
于 2020-07-03T14:14:42.903 に答える
-1

ファイルがWindowsに存在するかどうかを検出します。

bool DoesExistFile(std::wstring filePath)
{
    bool result = true;

    HANDLE fileHandle = CreateFile(
        filePath.c_str(),
        GENERIC_READ,
        0,
        NULL,
        OPEN_EXISTING,
        0,
        NULL);

    if ((fileHandle != NULL) && (fileHandle != INVALID_HANDLE_VALUE))
        CloseHandle(fileHandle);
    else
    {
        DWORD error = GetLastError();

        if ((error == ERROR_FILE_NOT_FOUND) || (error == ERROR_PATH_NOT_FOUND))
            result = false;
    }

    return result;
}
于 2021-07-15T14:17:42.007 に答える
-6

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

fstream file("file_name.txt");

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

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

于 2014-09-17T21:19:28.303 に答える