[c++] أسرع طريقة للتحقق من وجود ملف باستخدام C ++ / C ++ 11 / C قياسي؟



6 Answers

أستخدم هذه الشفرة ، إنها تعمل بشكل جيد معي حتى الآن. هذا لا يستخدم العديد من الميزات الفاخرة لـ C ++:

bool is_file_exist(const char *fileName)
{
    std::ifstream infile(fileName);
    return infile.good();
}
Question

أرغب في العثور على أسرع طريقة للتحقق من وجود ملف في C ++ 11 أو C ++ أو C معياري. لدي آلاف الملفات وقبل القيام بشيء عليها أحتاج إلى التحقق مما إذا كانت موجودة جميعها. ما الذي يمكنني كتابته بدلاً من /* SOMETHING */ في الوظيفة التالية؟

inline bool exist(const std::string& name)
{
    /* SOMETHING */
}



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.
}



أحتاج إلى وظيفة سريعة يمكنها التحقق مما إذا كان الملف موجودًا أم لا ، وإجابة PherricOxide تقريبًا ما أريده إلا أنه لا يقارن أداء boost :: filesystem :: موجود ووظائف مفتوحة. من النتائج المرجعية يمكننا أن نرى بسهولة ما يلي:

  • يعد استخدام الدالة stat أسرع طريقة للتحقق من وجود الملف. لاحظ أن نتائجي تتوافق مع إجابة PherricOxide.

  • أداء وظيفة boost :: filesystem :: قريبة جدا من وظيفة stat وهي أيضا محمولة. أوصي بهذا الحل إذا كان الوصول إلى المكتبات يمكن الوصول إليه من شفرتك.

النتائج القياسية التي تم الحصول عليها باستخدام Linux kernel 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();   



بدون استخدام مكتبات أخرى ، أرغب في استخدام مقتطف الشفرة التالي:

#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.




يعتمد ذلك على مكان وجود الملفات. على سبيل المثال ، إذا كان من المفترض أن يكونوا جميعًا في نفس الدليل ، فيمكنك قراءة جميع إدخالات الدليل في جدول تجزئة ثم التحقق من جميع الأسماء في جدول التجزئة. قد يكون هذا أسرع في بعض الأنظمة من التحقق من كل ملف على حدة. تعتمد أسرع طريقة للتحقق من كل ملف على حدة على النظام الخاص بك ... إذا كنت تكتب ANSI C ، فإن الطريقة الأسرع هي fopen لأنها الطريقة الوحيدة (قد يكون الملف موجودًا ولكن لا يمكن فتحه ، ولكنك ربما تريد فعلًا إمكانية الفتح في حالة تحتاج إلى "القيام بشيء ما على ذلك"). توفر كل من C ++ و POSIX و Windows خيارات إضافية.

بينما أنا في ذلك ، اسمحوا لي أن أشير إلى بعض المشاكل مع سؤالك. أنت تقول إنك تريد أسرع طريقة ، وأن لديك آلاف الملفات ، لكنك بعد ذلك تسأل عن الكود الخاص بالوظيفة لاختبار ملف واحد (وهذه الوظيفة صالحة فقط في C ++ ، وليس C). هذا يتعارض مع متطلباتك من خلال تقديم افتراض حول الحل ... حالة لمشكلة XY . أنت أيضا تقول "في معيار C + + 11 (أو) ج ++ (أو) ج" ... التي هي جميعا مختلفة ، وهذا أيضا غير متناسق مع متطلباتك للسرعة ... الحل الأسرع من شأنه أن ينطوي على تخصيص الرمز إلى نظام الهدف. يتم توضيح عدم التناسق في السؤال بحقيقة أنك قبلت إجابة توفر حلولاً معتمدة على النظام وليست قياسية C أو C ++.




إذا كنت بحاجة إلى التمييز بين ملف ودليل ، ففكر في التالي الذي يستخدم كلا من 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;
}



يمكنك أيضًا أن تفعل bool b = std::ifstream('filename').good(); . بدون تعليمات الفرع (مثل إذا) يجب أن يعمل بشكل أسرع لأنه يحتاج إلى استدعاء آلاف المرات.




Related