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




라이브러리 기능 (15)

나는 파일이 표준 C ++ 11, C ++ 또는 C에 있는지를 확인하는 가장 빠른 방법을 찾고 싶습니다. 수천 개의 파일이 있고 그 파일에 무언가를하기 전에 모든 파일이 있는지 확인해야합니다. /* SOMETHING */ 대신 다음 함수에서 쓸 수있는 것은 무엇입니까?

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

Answers

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

Windows에서 또 다른 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;
}

MFC를 사용하면 다음과 같이 할 수 있습니다.

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

여기서 FileName 은 존재를 확인하는 파일을 나타내는 문자열입니다.


참고 : C ++ 14에서 파일 시스템 TS 가 완료되고 채택되는 즉시 해결책은 다음을 사용하는 것입니다.

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

그리고 C ++ 17부터, 오직 :

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

글쎄 나는이 방법들을 각각 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() 함수는 내 시스템 (리눅스, g++ 컴파일 된 stat() 에서 최상의 성능을 제공했다. 표준 fopen 호출은 어떤 이유로 든 POSIX 함수 사용을 거부했을 때 최상의 선택이었다.


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
}

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

파일이있는 위치에 따라 다릅니다. 예를 들어, 모두 같은 디렉토리에 있다고 가정하면 모든 디렉토리 항목을 해시 테이블로 읽어 들여 해시 테이블에 대해 모든 이름을 확인할 수 있습니다. 일부 시스템에서는 각 파일을 개별적으로 검사하는 것보다 빠를 수도 있습니다. 각 파일을 개별적으로 검사하는 가장 빠른 방법은 시스템에 따라 다릅니다 ... ANSI C를 작성하는 경우 가장 빠른 방법은 파일이기 때문에 가능하지만 파일을 열 수는 없기 때문에 fopen . 그러나 if open ifable if 당신은 "그것에 뭔가를해야한다"). C ++, POSIX, Windows는 모두 추가 옵션을 제공합니다.

제가 그 동안 질문에 대한 몇 가지 문제점을 지적하겠습니다. 가장 빠른 방법을 원하고 수천 개의 파일을 가지고 있다고하지만, 단일 파일을 테스트하는 함수의 코드를 요청합니다.이 함수는 C가 아닌 C ++에서만 유효합니다. 이것은 해결책에 대한 가정을함으로써 요구 사항을 모순됩니다 ... XY 문제 의 경우. 또한 "표준 C ++ 11 (또는) C ++ (또는) C"... 모두 다르고, 이것은 또한 속도에 대한 요구 사항과 일치하지 않습니다 ... 가장 빠른 솔루션은 코드를 목표 시스템. 이 질문의 불일치는 시스템 의존적이고 표준 C 또는 C ++가 아닌 솔루션을 제공하는 대답을 받아 들인 사실에 의해 강조됩니다.


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

다른 라이브러리를 사용하지 않고 다음 코드 스 니펫을 사용하고 싶습니다.

#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 호환 시스템에서 크로스 플랫폼으로 작동합니다.


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

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

bool b = std::ifstream('filename').good(); 수행 할 수도 있습니다 bool b = std::ifstream('filename').good(); . if와 같은 분기 명령어가 없으면 수천 번 호출해야하므로 더 빨리 수행해야합니다.


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

 boost::filesystem::exists(fileName)

std::ifstream , is_open 과 같은 is_open 사용할 수 있습니다. 예를 들어 아래 코드와 같이 fail 할 수 있습니다. "cout"은 파일이 존재하는지 여부를 의미합니다.

이 answer 에서 인용


다음은 우리가 사용하는 것입니다 :

using System;

using System.IO;

namespace crmachine.CommonClasses
{

  public static class CRMPath
  {

    public static bool IsDirectory(string path)
    {
      if (path == null)
      {
        throw new ArgumentNullException("path");
      }

      string reason;
      if (!IsValidPathString(path, out reason))
      {
        throw new ArgumentException(reason);
      }

      if (!(Directory.Exists(path) || File.Exists(path)))
      {
        throw new InvalidOperationException(string.Format("Could not find a part of the path '{0}'",path));
      }

      return (new System.IO.FileInfo(path).Attributes & FileAttributes.Directory) == FileAttributes.Directory;
    } 

    public static bool IsValidPathString(string pathStringToTest, out string reasonForError)
    {
      reasonForError = "";
      if (string.IsNullOrWhiteSpace(pathStringToTest))
      {
        reasonForError = "Path is Null or Whitespace.";
        return false;
      }
      if (pathStringToTest.Length > CRMConst.MAXPATH) // MAXPATH == 260
      {
        reasonForError = "Length of path exceeds MAXPATH.";
        return false;
      }
      if (PathContainsInvalidCharacters(pathStringToTest))
      {
        reasonForError = "Path contains invalid path characters.";
        return false;
      }
      if (pathStringToTest == ":")
      {
        reasonForError = "Path consists of only a volume designator.";
        return false;
      }
      if (pathStringToTest[0] == ':')
      {
        reasonForError = "Path begins with a volume designator.";
        return false;
      }

      if (pathStringToTest.Contains(":") && pathStringToTest.IndexOf(':') != 1)
      {
        reasonForError = "Path contains a volume designator that is not part of a drive label.";
        return false;
      }
      return true;
    }

    public static bool PathContainsInvalidCharacters(string path)
    {
      if (path == null)
      {
        throw new ArgumentNullException("path");
      }

      bool containedInvalidCharacters = false;

      for (int i = 0; i < path.Length; i++)
      {
        int n = path[i];
        if (
            (n == 0x22) || // "
            (n == 0x3c) || // <
            (n == 0x3e) || // >
            (n == 0x7c) || // |
            (n  < 0x20)    // the control characters
          )
        {
          containedInvalidCharacters = true;
        }
      }

      return containedInvalidCharacters;
    }


    public static bool FilenameContainsInvalidCharacters(string filename)
    {
      if (filename == null)
      {
        throw new ArgumentNullException("filename");
      }

      bool containedInvalidCharacters = false;

      for (int i = 0; i < filename.Length; i++)
      {
        int n = filename[i];
        if (
            (n == 0x22) || // "
            (n == 0x3c) || // <
            (n == 0x3e) || // >
            (n == 0x7c) || // |
            (n == 0x3a) || // : 
            (n == 0x2a) || // * 
            (n == 0x3f) || // ? 
            (n == 0x5c) || // \ 
            (n == 0x2f) || // /
            (n  < 0x20)    // the control characters
          )
        {
          containedInvalidCharacters = true;
        }
      }

      return containedInvalidCharacters;
    }

  }

}




c++ c file stream