Самый быстрый способ проверить, существует ли файл с использованием стандартного С++/С++ 11/C?
Я хотел бы найти самый быстрый способ проверить, существует ли файл в стандартном С++ 11, С++ или C. У меня есть тысячи файлов и перед тем, как что-то делать с ними, мне нужно проверить, все ли они существуют. Что я могу написать вместо /* SOMETHING */
в следующей функции?
inline bool exist(const std::string& name)
{
/* SOMETHING */
}
Ответы
Ответ 1
Хорошо, я бросил вместе тестовую программу, которая запускала каждый из этих методов 100 000 раз, наполовину на файлы, которые существовали, и половина на файлы, которые этого не сделали.
#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);
}
Результаты за общее время для запуска 100 000 звонков, усредненных за 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.
Ответ 2
Я использую этот кусок кода, он работает со мной до сих пор. Это не использует многие причудливые функции С++:
bool is_file_exist(const char *fileName)
{
std::ifstream infile(fileName);
return infile.good();
}
Ответ 3
Замечание: в С++ 14 и как только файловая система TS будет завершена и принята, решение будет использовать:
std::experimental::filesystem::exists("helloworld.txt");
и поскольку С++ 17, только:
std::filesystem::exists("helloworld.txt");
Ответ 4
Это зависит от того, где находятся файлы. Например, если все они должны находиться в одном каталоге, вы можете прочитать все записи каталога в хэш-таблицу, а затем проверить все имена на хэш-таблицу. Этот может быть быстрее на некоторых системах, чем проверять каждый файл по отдельности. Самый быстрый способ проверить каждый файл в отдельности зависит от вашей системы... если вы пишете ANSI C, самый быстрый способ - fopen
, потому что это единственный способ (файл может существовать, но не быть открытым, но вы, вероятно, действительно хотите открыто, если вам нужно "что-то сделать" ). С++, POSIX, Windows предлагают дополнительные опции.
Пока я нахожусь на этом, позвольте мне указать на некоторые проблемы с вашим вопросом. Вы говорите, что хотите самый быстрый способ, и что у вас есть тысячи файлов, но затем вы просите код для функции протестировать один файл (и эта функция действительна только на С++, а не на C). Это противоречит вашим требованиям, сделав предположение о решении... случай проблемы XY. Вы также говорите "в стандартном С++ 11 (или) С++ (или) c"..., которые все разные, и это также не соответствует вашему требованию скорости... самое быстрое решение будет заключаться в адаптации кода к целевой системы. Непоследовательность в вопросе подчеркивается тем фактом, что вы приняли ответ, который дает решения, зависящие от системы, и не являются стандартными C или С++.
Ответ 5
Для тех, кому нравится boost:
boost::filesystem::exists(fileName)
Ответ 6
Без использования других библиотек мне нравится использовать следующий фрагмент кода:
#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-совместимых систем.
Ответ 7
То же, что предложено PherricOxide, но в C
#include <sys/stat.h>
int exist(const char *name)
{
struct stat buffer;
return (stat (name, &buffer) == 0);
}
Ответ 8
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.
}
Ответ 9
Еще 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;
}
Ответ 10
Вы также можете сделать bool b = std::ifstream('filename').good();
. Без инструкций ветвления (например, если) он должен выполняться быстрее, поскольку его нужно называть тысячами раз.
Ответ 11
Если вам нужно провести различие между файлом и каталогом, рассмотрите следующее, которое использует stat, который является самым быстрым стандартным инструментом, как показано PherricOxide:
#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;
}
Ответ 12
all_of (begin(R), end(R), [](auto&p){ exists(p); })
где R
- это ваша последовательность дорожных вещей, а exists()
- из будущего std или текущего повышения. Если вы откажетесь от своего собственного, держите его простым,
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
}
Ответ 13
Вы можете использовать std::ifstream
, std::ifstream
, например is_open
, fail
, например, как ниже код (cout "open" означает, что файл существует или нет):
![enter image description here]()
![enter image description here]()
цитируется из этого ответа
Ответ 14
Использование MFC возможно со следующим
CFileStatus FileStatus;
BOOL bFileExists = CFile::GetStatus(FileName,FileStatus);
Где FileName
- это строка, представляющая файл, который вы проверяете на наличие
Ответ 15
Мне нужна быстрая функция, которая может проверить, существует ли файл или нет, а ответ PherricOxide - это почти то, что мне нужно, кроме того, что он не сравнивает производительность boost :: filesystem :: существует и открывает функции. Из результатов теста мы легко видим, что:
-
Использование функции 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();
Ответ 16
В С++ 17:
#include <experimental/filesystem>
bool is_file_exist(std::string& str) {
namespace fs = std::experimental::filesystem;
fs::path p(str);
return fs::exists(p);
}
Ответ 17
Хотя существует несколько способов сделать это, наиболее эффективным решением вашей проблемы, вероятно, будет использование одного из предопределенных методов fstream, например good(). С помощью этого метода вы можете проверить, существует ли указанный вами файл.
fstream file("file_name.txt");
if (file.good())
{
std::cout << "file is good." << endl;
}
else
{
std::cout << "file isnt good" << endl;
}
Надеюсь, вы сочтете это полезным.