표준 C ++ / C ++ 11 / C를 사용하여 파일이 존재하는지 확인하는 가장 빠른 방법은 무엇입니까?


453

표준 C ++ 11, C ++ 또는 C에 파일이 있는지 확인하는 가장 빠른 방법을 찾고 싶습니다. 수천 개의 파일이 있으며 파일을 처리하기 전에 모든 파일이 존재하는지 확인해야합니다. /* SOMETHING */다음 함수 대신에 무엇을 쓸 수 있습니까?

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

2
boost::filesystem사용하는 것 같습니다 stat(). (문서에서 가정) FS 호출에 대해 훨씬 빨리 할 수 ​​있다고 생각하지 않습니다. 빠른 작업을 수행하는 방법은 "수천 개의 파일을 보지 마십시오."
— millimoose

16
TOCTOU 질문 : exist () 확인과 "무엇을 수행" 간에 파일이 연결되어 있지 않은지 어떻게 알 수 있습니까?
— 순례자

7
@pilcrow 좋은 지적이지만 그 정도의 정확성이 필요하지 않은 상당히 다양한 응용 프로그램이 있습니다. 예를 들어 git push초기 더러운 점검 후에 작업 트리를 건드리지 않도록 신경 쓰지 않을 것입니다.
— millimoose

9
'필요하지 않은 C / C ++ 구현을 생각할 수 없습니다'-Windows는 POSIX 환경을 제공하지 않습니다.
— 짐 발터

답변:


778

글쎄, 나는이 방법들 각각을 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); 
}

총 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++) 에서 최고의 성능을 제공했으며 fopen어떤 이유로 POSIX 함수 사용을 거부하면 표준 호출이 가장 좋습니다.


31
위의 방법 중 어느 것도 존재 여부를 확인하지 않고 접근성을 검사합니다. 그래도 존재를 확인하는 단일 표준 C 또는 C ++ 방법을 모른다.
— IInspectable

10
stat()존재를 확인하는 것 같습니다.
— el.pescado

105
이것을 사용하는 사람은 #include <sys / stat.h>를 기억해야합니다. 그렇지 않으면 잘못된 통계를 사용하려고합니다.
— Katianie

23
ifstream 메소드 f.close()의 경우 함수의 끝에서 f가 범위를 벗어날 때 필요하지 않습니다 . 그래서 return f.good()바꾸기 수있는 if블록을?
— ilent2

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
스튜디오 2013 비주얼 MS에서는이 기능에 따라 사용할 수 있습니다std::tr2::sys::exists("helloworld.txt");
— 콘스탄틴

3
실제로 실제로는 std::exists혼란스럽지 않기를 바랍니다 (생각하십시오 : 세트와 같은 STL 컨테이너에 존재합니다).
— einpoklum

3
Visual Studio 2015에서도 :#include <experimental/filesystem> bool file_exists(std::string fn) { std::experimental::filesystem::exists("helloworld.txt"); }
— Orwellophile

1
잊지 마세요#include <experimental/filesystem>
— Mohammed Noureldin 2018 년

112

나는이 코드를 사용한다. 지금까지 나와 함께 작동한다. 이것은 C ++의 멋진 기능을 많이 사용하지 않습니다.

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

8
그러나 다른 프로그램에 의해 파일이 잠겨 있거나 파일에 액세스 할 수 없으면 실패 할 수 있습니다.
— Jet

2
스트림을 닫아야합니까?
— Mo0gles

29
@ Mo0gles : 종료시 ifstream소멸자가 호출 is_file_exist되고 스트림이 닫힙니다.
— Isaac Isaac

2
C ++ 11부터 bool 연산자를 사용하여 한 줄로 할 수 있습니다. 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 (또는) c ++ (또는) c"에서 ... 모든 것이 다르며, 이것은 또한 속도에 대한 요구 사항과 일치하지 않습니다 ... 가장 빠른 해결책은 코드를 대상 시스템. 문제의 불일치는 시스템에 따라 다르며 표준 C 또는 C ++가 아닌 솔루션을 제공하는 답변을 수락했다는 사실에 의해 강조됩니다.


25

부스트를 좋아하는 사람들을 위해 :

 boost::filesystem::exists(fileName)

5
부스트는 일반적으로 매우 느립니다.
— Serge Rogatch

4
대부분의 응용 프로그램 파일이 검사가 성능에 중요하지 않은 존재
— anhoppe

29
고성능 응용 프로그램의 모든 측면에 최적화가 필요한 것은 아닙니다. 예를 들어, 응용 프로그램 자체에 C ++의 성능 이점이 필요할 수 있지만 명령 줄 또는 구성 파일을 읽는 것은 복잡하고 속도가 필요하지 않을 수 있습니다. 이러한 경우 부스트를 피하면 안티 패턴 목록에서 휠 재창조가 높아집니다.
— evoskuil

5
@SergeRogatch boost :: filesystem :: exists는 매우 느리지 않습니다. 자세한 내용은 벤치 마크 결과를 참조하십시오.
— hungptit

3
"부스트는 일반적으로 매우 느리다"-이것은 거짓이며, 주장의 범위가 무엇인지 명확하지 않습니다. Boost는 다른 저자의 많은 패키지를 포함하지만 고품질로 심사되었습니다. "대부분의 응용 프로그램에서 파일이 존재하는지 확인하는 것은 성능이 중요하지 않습니다."-OP는 매우 많은 수의 파일을 확인하여 속도를 요구했습니다. "성능이 중요하지 않은 경우 C ++ 사용에도 아무런 의미가 없습니다."– 또 다른 잘못된 설명 (및 주제 외). 대부분의 소프트웨어는 상점 에서 작성되었으며 언어 선택을 요구 하는 시스템의 일부입니다 .
— Jim Balter 8

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에서 작동합니까? 나는 맥이 없지만 맥도 포함될 수있을 것으로 기대한다 unistd.h. 아마도 첫 번째 #ifdef는 창과 관련이 있어야합니까?
— matth

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에 해당하는 항목을 게시했습니다.
— 라몬 라 피에트라

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 브랜치를 사용하는 대신 "반환 (부울) 파일"만하면됩니다.
— Nik Haldimann

실제 경우에 파일을 닫는 것을 잊지 마십시오. 프로그램의 전체 런타임 동안 파일을 열어두면 메모리 누수 유형입니다. 파일이 잠겨 있다는 사실은 말할 것도없고 파일이 존재한다는 것을 알면 읽을 수 없습니다 .. add : file.close () 두 번째로.
— Bill Moore

2
두 번째 생각에 아마도 명시 적으로 닫을 필요가 없습니다 ... 나는 ifstream이 RAII (Resource Acquisition Is Initialization) 인 것을 잊어 버렸고 소멸자로부터 범위를 벗어날 때 스스로 정리할 것입니다 ... 말할 수 있습니까 ... 요즘 가비지 수집기 언어로 세뇌를 당합니다 ...
— Bill Moore

@BillMoore 두 번째 코멘트는 정확합니다. 이 페이지에 언급 된 많은 다른 의견 close()은 필요하지 않습니다.
— Keith 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;
}

OpenFile은 ANSI 전용이며 128 자로 제한됩니다 .
— David Bremner

5
GetFileAttributes버전은 기본적으로 Windows에서 그것을 할 수있는 표준 방법입니다.
— Felix Dombek

나는 이것이 오래되었다는 것을 알고 있지만 사용자가 파일을 읽을 수는 있지만 파일 속성을 읽을 수없는 경우 세 번째 경우에는 어떻게됩니까?
— Quest

6

당신은 또한 할 수 있습니다 bool b = std::ifstream('filename').good();. 분기 명령어가없는 경우 (같은 경우) 수천 번 호출해야하므로 더 빠르게 수행해야합니다.


허용 된 답변에서 알 수 있듯이 이것은 사실이 아닙니다. if에 넣든 넣지 않든 심각한 컴파일러는 아마도 동일한 코드를 방출 할 것입니다 . 일반 C 변형과 비교하여 ifstream 객체를 구성하면 (스택에 있더라도) 추가 오버 헤드가 발생합니다.
— minexew

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

4

파일이 존재하는지 여부를 확인할 수있는 빠른 기능이 필요하며 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();   

4

당신은 사용할 수 있습니다 std::ifstream, 같은 funcion을 is_open, fail코드합니다 (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로 제한됩니다. 워드 프로세서는 해결 방법을 설명하는 경우 는 절대 경로, 유니 코드를 사용하고 경로 이름에 특별한 접두어 문자열을 앞에 추가. 어쨌든 우리는 Windows 관련 응답을 접하고 있다고 생각합니다.
— John

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가 제공 한 답변보다 덜 유익합니다.
— Jim Balter 8

2
C ++ 17에서 파일 시스템은 더 이상 실험적이지 않습니다
— Quest

0

MFC를 사용하면 다음과 같이 가능합니다.

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

FileName존재 여부를 확인하는 파일을 나타내는 문자열은 어디에 있습니까?


0

파일이 존재하는지 확인하는 단 하나의 빠른 방법이 있으며 파일을 읽을 권한이 있으면 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의 사전 정의 된 방법 중 하나를 사용하는 것입니다 . 이 방법을 사용하면 지정한 파일이 있는지 여부를 확인할 수 있습니다.

fstream file("file_name.txt");

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

이 정보가 도움이 되길 바랍니다.


4
이 코드는 파일이 존재하지 않는 경우 파일을 작성하므로 결과는 항상 참입니다. ifstream을 사용하거나 openmode 매개 변수를 올바르게 설정해야합니다.
— Lubo Antonov
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.