Najszybszy sposób sprawdzenia, czy plik istnieje przy użyciu standardowego C++/C++11 / C?
Chciałbym znaleźć najszybszy sposób, aby sprawdzić, czy plik istnieje w standardowym C++11, C++, lub C. mam tysiące plików i zanim coś na nich zrobię, muszę sprawdzić, czy wszystkie z nich istnieją. Co mogę napisać zamiast /* SOMETHING */
w poniższej funkcji?
inline bool exist(const std::string& name)
{
/* SOMETHING */
}
17 answers
Cóż, rzuciłem razem program testowy, który uruchomił każdą z tych metod 100,000 razy, w połowie na plikach, które istniały, a w połowie na plikach, które nie.
#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);
}
Wyniki dla łącznego czasu uruchomienia 100 000 połączeń uśrednionych w 5 biegach,
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**
Funkcja stat()
zapewniała najlepszą wydajność w moim systemie (Linux, skompilowana z g++
), A standardowe wywołanie fopen
było najlepszym rozwiązaniem, jeśli z jakiegoś powodu odmówisz korzystania z funkcji POSIX.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-05 11:31:18
Używam tego kawałka kodu, jak na razie Działa OK. To nie używa wielu fantazyjnych funkcji C++:
bool is_file_exist(const char *fileName)
{
std::ifstream infile(fileName);
return infile.good();
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-07 16:45:31
Uwaga: W C++14 i jak tylko system plików TS zostanie ukończony i przyjęty, rozwiązaniem będzie użycie:
std::experimental::filesystem::exists("helloworld.txt");
A od C++17 tylko:
std::filesystem::exists("helloworld.txt");
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-16 23:50:31
To zależy od tego, gdzie znajdują się pliki. Na przykład, jeśli wszystkie powinny znajdować się w tym samym katalogu, możesz odczytać wszystkie wpisy katalogu w tabeli hash, a następnie sprawdzić wszystkie nazwy w tabeli hash. To Może być szybsze na niektórych systemach niż sprawdzanie KAŻDEGO pliku osobno. Najszybszy sposób sprawdzenia KAŻDEGO pliku indywidualnie zależy od systemu ... jeśli piszesz ANSI C, najszybszym sposobem jest fopen
, ponieważ jest to jedyny sposób (plik może istnieć, ale nie być openable, ale prawdopodobnie naprawdę chcesz openable, jeśli chcesz "coś na nim zrobić"). C++, POSIX, Windows wszystkie oferują dodatkowe opcje.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-20 10:29:30
Dla tych, którzy lubią boost:
boost::filesystem::exists(fileName)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-21 08:30:10
Bez używania innych bibliotek, lubię używać poniższego fragmentu kodu:
#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;
}
To działa międzyplatformowo dla Systemów Windows i zgodnych z POSIX.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-05 04:07:48
To samo, co sugeruje PherricOxide, ale w C
#include <sys/stat.h>
int exist(const char *name)
{
struct stat buffer;
return (stat (name, &buffer) == 0);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-28 03:32:33
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.
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-08 15:54:45
Kolejne 3 opcje pod windows:
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;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-22 15:18:18
Możesz również zrobić bool b = std::ifstream('filename').good();
. Bez instrukcji gałęzi(jak if) musi działać szybciej, ponieważ musi być wywoływana tysiące razy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-25 05:48:35
Jeśli chcesz odróżnić Plik od katalogu, rozważ następujące, które oba używają stat, które jest najszybszym standardowym narzędziem, jak pokazano w 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;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-21 13:30:22
all_of (begin(R), end(R), [](auto&p){ exists(p); })
Gdzie R
jest Twoim ciągiem rzeczy podobnych do ścieżki, a {[4] } jest z przyszłego std lub obecnego boost. Jeśli kręcisz własnym, trzymaj to prosto,
bool exists (string const& p) { return ifstream{p}; }
Rozwiązanie rozgałęzione nie jest absolutnie straszne i nie pożera deskryptorów plików,
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
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-25 00:57:03
Potrzebuję szybkiej funkcji, która może sprawdzić, czy plik istnieje czy nie i odpowiedź PherricOxide jest prawie taka, jakiej potrzebuję, z wyjątkiem tego, że nie porównuje wydajności boost::filesystem::exists i funkcji open. Z wyników benchmarku możemy łatwo zauważyć, że:
Korzystanie z funkcji stat jest najszybszym sposobem sprawdzenia, czy plik istnieje. Zauważ, że moje wyniki są zgodne z odpowiedzią PherricOxide.
Wydajność funkcji boost:: filesystem:: exists jest bardzo zbliżony do funkcji stat i jest również przenośny. Polecam to rozwiązanie, jeśli biblioteki boost są dostępne z twojego kodu.
Wyniki porównawcze uzyskane z jądrem Linuksa 4.17.0 i 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
Poniżej znajduje się mój kod odniesienia:
#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();
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-05 04:51:34
Możesz użyć std::ifstream
, funcion jak is_open
, fail
, na przykład jak poniżej (cout "open" oznacza, że plik istnieje lub nie):
Cytowane z tego odpowiedź
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-12 08:59:55
Korzystanie z MFC jest możliwe za pomocą następujących
CFileStatus FileStatus;
BOOL bFileExists = CFile::GetStatus(FileName,FileStatus);
Gdzie {[1] } jest łańcuchem znaków reprezentującym plik, który sprawdzasz pod kątem istnienia
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-28 03:32:38
W 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);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-28 16:25:59
Chociaż istnieje kilka sposobów, aby to zrobić, najskuteczniejszym rozwiązaniem problemu byłoby prawdopodobnie użycie jednej z predefiniowanych metod fstream, takich jak good () . Za pomocą tej metody możesz sprawdzić, czy podany plik istnieje, czy nie.
fstream file("file_name.txt");
if (file.good())
{
std::cout << "file is good." << endl;
}
else
{
std::cout << "file isnt good" << endl;
}
Mam nadzieję, że to ci się przyda.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-17 21:19:28