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





files in (13)


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

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

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



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
}



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

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




على الرغم من وجود العديد من الطرق للقيام بذلك ، قد يكون الحل الأكثر فعالية لمشكلتك هو استخدام أحد الأساليب المحددة مسبقًا لـ fstream مثل good () . باستخدام هذه الطريقة ، يمكنك التحقق مما إذا كان الملف الذي حددته موجودًا أم لا.

fstream file("file_name.txt");

if (file.good()) 
{
    std::cout << "file is good." << endl;
}
else 
{
    std::cout << "file isnt good" << endl;
}

آمل أن تجد هذا مفيدًا.




حسناً ، لقد قمت بإلقاء برنامج اختبار يدير كل واحدة من هذه الطرق 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); 
}

نتائج إجمالي الوقت لتشغيل 100000 مكالمات متوسطها أكثر من 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 لسبب ما.




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



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

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



نفس ما اقترحه PherricOxide ولكن في C

#include <sys/stat.h>
int exist(const char *name)
{
  struct stat   buffer;
  return (stat (name, &buffer) == 0);
}



باستخدام MFC ممكن مع التالي

CFileStatus FileStatus;
BOOL bFileExists = CFile::GetStatus(FileName,FileStatus);

حيث FileName عبارة عن سلسلة تمثل الملف الذي تقوم بالتحقق من وجوده




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




ملاحظة: في C ++ 14 وبمجرد الانتهاء من TS لنظام الملفات واعتماده ، سيكون الحل هو:

std::experimental::filesystem::exists("helloworld.txt");

ونأمل في C ++ 17 ، فقط:

std::filesystem::exists("helloworld.txt");



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

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




على غرار this السؤال.

في جوهرها ، يعني هذا أن Bar الطريقة لن يقوم بتعديل المتغيرات الخاصة بالأعضاء غير mutable في Foo .





c++ c file stream