표준 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.