我想找到在标准C++11、14、17或C中检查文件是否存在的最快方法。我有数千个文件,在对它们进行任何操作之前,我需要检查它们是否都存在。在下面的函数中,可以用什么代替/* SOMETHING */
?
inline bool exist(const std::string& name)
{
/* SOMETHING */
}
您还可以执行bool b = std::ifstream('filename').good();
。没有分支指令(如if),它必须更快地执行,因为需要调用数千次。
#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;
}
&&
(如果您每次尝试将其中一个叶节点设置为true时都始终按照此过程进行,则不需要递归下降到其他子节点,因为当且仅当它们的所有子节点都为真时,它们才为真)。
std::filesystem::directory_iterator
。boost::filesystem::directory_iterator
,我假设它可以在旧版本的C++中工作。dirent.h
中的opendir
和readdir
。那是一个标准的C接口,只不过是在POSIX中标准化而不是在C标准本身中。它可以在Mac OS、Linux、所有BSD、其他UNIX/UNIX-like系统以及任何其他POSIX/SUS系统上直接使用。对于Windows,有一个dirent.h
实现,你只需要下载并将其放入你的include路径即可。getdents64
来指定缓冲区大小以优化性能。FindFirstFileEx
与FindExInfoBasic
和FIND_FIRST_EX_LARGE_FETCH
,但很多开源库(如上述的dirent.h
)似乎并不这样做。但是对于需要处理比最近几个Windows版本旧的内容的代码,您可以只使用简单的FindFirstFile
而不使用额外的标志。dirread
或dirreadall
(如果您可以安全地假设您拥有足够的内存来容纳整个目录内容)。如果您想要更多关于性能缓冲区大小的控制,请使用普通的read
或read
并解码目录条目数据-它们采用文档化的机器无关格式,并且我认为提供了辅助函数。
我不知道其他操作系统的情况。
我可能会稍后编辑这个答案并进行一些测试。其他人也可以编辑测试结果。
all_of (begin(R), end(R), [](auto&p){ exists(p); })
其中R
是您的路径序列,exists()
来自未来的std或当前的boost。如果您自己创建,请保持简单。
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
}
PathFileExists
函数仅支持 MAX_PATH
(260) 字符的路径长度;而 GetFileAttributes
函数则没有此限制。 - Felix DombekGetFileAttributes
也是受 MAX_PATH 限制的。文档描述了一种解决方法——如果你使用绝对路径、Unicode,并在路径名前添加一个特殊前缀字符串。我认为我们已经偏离了与 Windows 相关的响应。 - JohnGetFileAttributesW
没有限制。 - Laurie Stearn在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);
}
其实有更简单的方法。
#include <fstream>
#include <iostream>
void FileExists(std::string myfile){
std::ifstream file(myfile.c_str());
if (file) {
std::cout << "file exists" << std::endl;
}
else {
std::cout << "file doesn't exist" << std::endl;
}
}
int main() {
FileExists("myfile.txt");
return 0;
}
#include <iostream>
#include <fstream>
using namespace std;
void main(){
SearchFile("test.txt");
}
bool SearchFile(const char *file)
{
ifstream infile(file);
if (!infile.good())
{
// If file is not there
exit(1);
}
}
检查文件是否存在并且是否有权限读取的最快方法就是使用 C 语言,这种方式更快速并且可以在任何版本的 C++ 中使用。
解决方案:在 C 中,有一个名为 errno.h 的库,其中包含一个外部(全局)整数变量称为 errno,其中包含可用于识别错误类型的数字。
#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;
}
测试文件是否存在的最快、最安全的方法不是单独/明确地进行测试,而是看看是否能找到一种替代普通方法的方式。
if(exists(file)) { /* point A */
/* handle existence condition */
return;
}
do_something_with(file); /* point B */
通过改进
r = do_something_with_unless_exists(file);
if(r == 0)
success;
else if(errno == EEXIST)
/* handle existence condition */
else
/* handle other error */
do_something_with_unless_exists
操作的存在。通常有方法可以做到这一点,但有时需要四处搜索。
创建文件:使用O_CREAT
和O_EXCL
调用open()
。
在纯C中创建文件,如果您有C11:使用"wx"
调用fopen()
。(我昨天才了解到这个。)
创建目录:只需调用mkdir()
并检查errno == EEXIST
。
获取锁定:任何值得其盐的锁定系统都已经具有原子获取锁定(只要没有其他人拥有它)的基本功能。
(还有其他方法,但这些是我现在能想到的。)
[注:在Unix早期,普通进程没有专门的设施可用于进行锁定,因此,如果您想设置互斥锁,则通常通过创建某个特定的空目录来实现,因为mkdir
系统调用始终具有根据先前的存在或不存在而成功或失败的能力,具有原子性。]
git push
命令可能不会在初始脏检查后再次确认您是否触及了工作树。 - millimoose