표준 C ++ / C ++ 11 / C를 사용하여 파일이 존재하는지 확인하는 가장 빠른 방법은 무엇입니까?
표준 C ++ 11, C ++ 또는 C에 파일이 있는지 확인하는 가장 빠른 방법을 찾고 싶습니다. 수천 개의 파일이 있으며 파일을 처리하기 전에 모든 파일이 존재하는지 확인해야합니다. /* SOMETHING */
다음 함수 대신 무엇을 쓸 수 있습니까?
inline bool exist(const std::string& name)
{
/* SOMETHING */
}
글쎄, 나는이 방법들 각각을 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 함수 사용을 거부하면 표준 호출이 가장 좋습니다.
비고 : C ++ 14에서 파일 시스템 TS 가 완성되고 채택되 자마자 해결책은 다음과 같습니다.
std::experimental::filesystem::exists("helloworld.txt");
그리고 C ++ 17부터는
std::filesystem::exists("helloworld.txt");
나는이 코드를 사용한다. 지금까지 나와 함께 작동한다. 이것은 C ++의 멋진 기능을 많이 사용하지 않습니다.
bool is_file_exist(const char *fileName)
{
std::ifstream infile(fileName);
return infile.good();
}
파일이있는 위치에 따라 다릅니다. 예를 들어, 모두 동일한 디렉토리에 있어야하는 경우 모든 디렉토리 항목을 해시 테이블로 읽은 다음 해시 테이블과 비교하여 모든 이름을 확인할 수 있습니다. 이 수 개별적으로 각 파일을 검사하는 것보다 일부 시스템 빠르다. 각 파일을 개별적으로 확인하는 가장 빠른 방법은 시스템에 따라 다릅니다 ... ANSI C를 작성하는 경우 가장 빠른 방법은 fopen
파일이 유일한 방법이기 때문입니다 (파일이 존재할 수는 있지만 열 수는 없지만 실제로는 열 수 있기를 원할 것입니다) "그 위에 무언가를해야한다"). C ++, POSIX, Windows는 모두 추가 옵션을 제공합니다.
내가 문제를 해결하는 동안 귀하의 질문에 몇 가지 문제를 지적하겠습니다. 가장 빠른 방법을 원하고 수천 개의 파일이 있다고 말하지만 단일 파일을 테스트하는 함수에 대한 코드를 요청하십시오 (그리고 그 함수는 C가 아닌 C ++에서만 유효합니다). 이것은 XY 문제 의 경우 솔루션에 대한 가정을함으로써 요구 사항과 모순됩니다 . 당신은 또한 "표준 c ++ 11 (또는) c ++ (또는) c"에서 ... 모든 것이 다르며, 이것은 또한 속도에 대한 요구 사항과 일치하지 않습니다 ... 가장 빠른 해결책은 코드를 대상 시스템. 문제의 불일치는 시스템에 따라 다르며 표준 C 또는 C ++이 아닌 솔루션을 제공하는 답변을 수락했다는 사실에 의해 강조됩니다.
부스트를 좋아하는 사람들을 위해 :
boost::filesystem::exists(fileName)
다른 라이브러리를 사용하지 않고 다음 코드 스 니펫을 사용하고 싶습니다.
#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 호환 시스템에 대해 크로스 플랫폼에서 작동합니다.
PherricOxide가 제안한 것과 동일하지만 C
#include <sys/stat.h>
int exist(const char *name)
{
struct stat buffer;
return (stat (name, &buffer) == 0);
}
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.
}
창에서 다른 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;
}
당신은 또한 할 수 있습니다 bool b = std::ifstream('filename').good();
. 분기 명령어가없는 경우 (if와 같음) 수천 번 호출해야하므로 더 빠르게 수행해야합니다.
파일과 디렉토리를 구별해야하는 경우 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;
}
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();
당신은 사용할 수 있습니다 std::ifstream
, 같은 funcion을 is_open
, fail
코드합니다 (cout을 "공개"란 파일 존재 여부) 아래로, 예를 들어 :
이 답변 에서 인용
MFC를 사용하면 다음과 같이 가능합니다.
CFileStatus FileStatus;
BOOL bFileExists = CFile::GetStatus(FileName,FileStatus);
FileName
존재 여부를 확인하는 파일을 나타내는 문자열은 어디에 있습니까?
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);
}
이를 수행하는 여러 가지 방법이 있지만 문제에 대한 가장 효율적인 해결책은 good () 과 같은 fstream의 사전 정의 된 방법 중 하나를 사용하는 것입니다 . 이 방법을 사용하면 지정한 파일이 있는지 여부를 확인할 수 있습니다.
fstream file("file_name.txt");
if (file.good())
{
std::cout << "file is good." << endl;
}
else
{
std::cout << "file isnt good" << endl;
}
이 정보가 도움이 되길 바랍니다.
'Programing' 카테고리의 다른 글
파이썬에서 폴더의 내용을 삭제하는 방법? (0) | 2020.02.23 |
---|---|
테이블의 전체 행을 링크로 클릭 가능하게 만드는 방법은 무엇입니까? (0) | 2020.02.23 |
vi / Vim에서 여러 줄을 선택할 때 텍스트를 어떻게 삽입합니까? (0) | 2020.02.23 |
JavaScript Date를 자정으로 초기화하는 가장 좋은 방법은 무엇입니까? (0) | 2020.02.23 |
커밋 된 파일에 .gitignore 적용 (0) | 2020.02.23 |