使用标准C ++ / C ++ 11 / C来检查文件是否存在的最快方法?
我想find最快的方法来检查标准C ++ 11,C ++或C中是否存在一个文件。我有成千上万的文件,在做些事情之前,我需要检查它们是否都存在。 在下面的函数中,我可以写什么而不是/* SOMETHING */
?
inline bool exist(const std::string& name) { /* SOMETHING */ }
那么我扔了一个testing程序,运行这些方法的每一个10万次,一半的文件存在,一半的文件没有。
#include <sys/stat.h> #include <unistd.h> #include <string> 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次呼叫的总时间的结果,
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 ++编译)上提供了最好的性能,如果由于某种原因拒绝使用POSIX函数,则标准fopen调用是最好的select。
我使用这段代码,到目前为止,它可以与我一起工作。 这不使用C ++的许多奇特function:
bool is_file_exist(const char *fileName) { std::ifstream infile(fileName); return infile.good(); }
备注:在C ++ 14中,一旦文件系统TS完成并采用,解决scheme将使用:
std::experimental::filesystem::exists("helloworld.txt");
并希望在C ++ 17中,只有:
std::filesystem::exists("helloworld.txt");
这取决于文件所在的位置。 例如,如果它们都应该在同一个目录中,那么可以将所有目录条目读入一个散列表,然后根据散列表检查所有的名称。 这在某些系统上可能会比单独检查每个文件更快。 检查每个文件的最快方法取决于你的系统…如果你正在编写ANSI C,最快的方法是fopen
因为这是唯一的方法(一个文件可能存在但不能打开,但你可能真的想打开如果你需要“做些什么”)。 C ++,POSIX,Windows都提供了其他选项。
当我在这里,让我指出你的问题有一些问题。 你说你想要最快的方法,而且你有成千上万的文件,但是你要求一个函数的代码来testing一个文件(而且这个函数只在C ++中有效,而不是在C中有效)。 这与您的要求相矛盾,通过对解决scheme进行假设来解决XY问题 。 你也说“在标准的C + + 11(或)C + +(或)C”…这是不同的,这也是不符合您的速度要求…最快的解决scheme将涉及到剪裁代码目标系统。 问题的不一致性突出performance在您已经接受了一个答案,该答案提供了依赖于系统的解决scheme,而不是标准的C或C ++。
对于那些喜欢提升的人:
boost::filesystem::exists(fileName)
与PherricOxidebuild议的一样,但在C中
#include <sys/stat.h> int exist(char *name) { struct stat buffer; return (stat (name, &buffer) == 0); }
不使用其他库,我喜欢使用下面的代码片段:
#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兼容系统的跨平台。
inline bool exist(const std::string& name) { ifstream file(name); if(!file) // If the file was not found, then file is 0, ie !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; }
3
inline bool exist(const std::string& name) { return GetFileAttributes(name.c_str()) != INVALID_FILE_ATTRIBUTES; }
你也可以做bool b = std::ifstream('filename').good();
。 如果没有分支指令(比如if),它必须执行得更快,因为它需要被调用数千次。
all_of (begin(R), end(R), [](auto&p){ exists(p); })
其中R
是你类似path的事物序列, exists()
是来自未来的标准或当前的提升。 如果你推出自己的,保持简单,
bool exists (string const& p) { return ifstream{p}; }
分支解决scheme不是绝对可怕的,它不会捕获文件描述符,
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演示的最快的标准工具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; }
虽然有几种方法可以做到这一点,但最有效的解决scheme可能是使用fstream的预定义方法之一(如good()) 。 用这个方法你可以检查你指定的文件是否存在。
fstream file("file_name.txt"); if (file.good()) { std::cout << "file is good." << endl; } else { std::cout << "file isnt good" << endl; }
我希望你觉得这个有用。