我想找到在标准C++11、14、17或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);
}
总共运行 100,000 次调用的时间结果,平均分成 5 组如下:
方法 | 时间 |
---|---|
exists_test0 (使用 ifstream) |
0.485 秒 |
exists_test1 (使用 FILE fopen) |
0.302 秒 |
exists_test2 (使用 posix access()) |
0.202 秒 |
exists_test3 (使用 posix stat()) |
0.134 秒 |
在我的系统上(Linux,编译器为 g++
),stat()
函数表现最佳。如果您出于某种原因拒绝使用 POSIX 函数,则标准的 fopen
调用是您最好的选择。
stat()
似乎是用来检查文件是否存在。 - el.pescado - нет войнеf.close()
,因为在函数结束时 f
将超出作用域。所以 return f.good()
可以替换掉 if
代码块,这样做是可行的。 - ilent2注意:在C++14中并且一旦filesystem TS完成并被采纳,解决方案将是使用:
std::experimental::filesystem::exists("helloworld.txt");
而自C++17以来,仅限于:
std::filesystem::exists("helloworld.txt");
std::exists
,那样会相当令人困惑(类似于在 STL 容器中的 set 中存在) 。 - einpoklum#include
bool file_exists(std::string fn) {
return std::experimental::filesystem::exists(fn);
}
- Orwellophile#include <experimental/filesystem>
。 - Mohammed Noureldinstdc++fs
库。例如:target_link_libraries(<可执行文件名称> stdc++fs)
。 - biendltb我使用这段代码,到目前为止它运行良好。它并没有使用C++的很多花哨特性:
bool is_file_exist(const char *fileName)
{
std::ifstream infile(fileName);
return infile.good();
}
ifstream
析构函数将在 is_file_exist
结束时被调用,并关闭流。 - Isaacreturn std::ifstream(fileName);
的意思是返回一个打开指定文件的输入流对象。 - emlaireturn static_cast<bool>(std::ifstream(fileName));
。如果没有static_cast,编译器会报错。 - user4223038对于喜欢增加速度的人:
boost::filesystem::exists(fileName)
std::filesystem::exists(fileName)
这取决于文件所在位置。例如,如果它们都应该在同一个目录中,则可以将所有目录条目读入哈希表中,然后检查所有名称是否与哈希表匹配。这种方法在某些系统上可能比逐个检查每个文件更快。逐个检查每个文件的最快方法取决于您的系统……如果您正在编写ANSI C,最快的方法是使用fopen
,因为这是唯一的方法(文件可能存在但无法打开,但如果您需要“对其进行操作”,则您可能确实希望能够打开)。C ++、POSIX、Windows都提供了其他选项。
不使用其他库,我喜欢使用以下代码片段:
#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 标准的系统。
unistd.h
。也许第一个#ifdef
应该是特定于Windows的? - matth按照PherricOxide的建议,但使用C语言。
#include <sys/stat.h>
int exist(const char *name)
{
struct stat buffer;
return (stat (name, &buffer) == 0);
}
我需要一个快速的函数来检查文件是否存在。PherricOxide的答案几乎符合我的需求,但它没有比较boost::filesystem::exists和open函数的性能。从基准测试结果中,我们可以很容易地看到:
使用stat函数是检查文件是否存在的最快方法。请注意,我的结果与PherricOxide的答案一致。
boost::filesystem::exists函数的性能非常接近stat函数,并且它也是可移植的。如果您的代码可以访问boost库,我会推荐使用这个解决方案。
基准测试结果是在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();
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.
}
close()
不是必需的。 - Keith Minline 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;
}
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;
}
git push
命令可能不会在初始脏检查后再次确认您是否触及了工作树。 - millimoose