قراءة ملف سطرًا بسطر في C++: ifstream و5 أخطاء قاتلة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

لماذا يكسر قراءة ملف بسيطة في C++ الكود حتى لدى المحترفين؟

\n\n

تخيل موقفًا: أنت تكتب محللًا لملفات الإعدادات، السجلات، أو CSV. يبدو كل شيء بسيطًا — فتح ملف، قراءة سطر تلو الآخر، معالجته. لكن في الواقع، سؤال "Read file line by line using ifstream in C++" على Stack Overflow يجمع آلاف المشاهدات ومئات التعليقات. لماذا؟ لأن الشيطان، كما هو الحال دائمًا، يكمن في التفاصيل.

\n\n

في هذه المقالة، لن نعرض فقط كيفية قراءة ملف سطرًا بسطر بشكل صحيح. سنحلل أكثر 5 أخطاء شيوعًا وخطورة التي تحول الكود العامل إلى كومة من الأخطاء. ستتعرف لماذا while (!file.eof()) هو شر، وكيف لا تفقد السطر الأخير، وماذا تفعل مع الملفات الثنائية. هيا بنا!

\n\n

الصيغة الأساسية: كيفية فتح ملف وقراءة سطر

\n\n

لنبدأ بالأساسيات. الفئة std::ifstream (input file stream) هي أداتك الرئيسية لقراءة الملفات. إليك مثال عملي بسيط:

\n\n
#include <iostream>\n#include <fstream>\n#include <string>\n\nint main() {\n    std::ifstream file("example.txt");\n    std::string line;\n\n    if (file.is_open()) {\n        while (std::getline(file, line)) {\n            std::cout << line << std::endl;\n        }\n        file.close();\n    } else {\n        std::cerr << "خطأ في فتح الملف!" << std::endl;\n    }\n    return 0;\n}
\n\n

يبدو أن ما الذي يمكن أن يحدث خطأ؟ لكن هذا ما سنراه.

\n\n

الخطأ رقم 1: استخدام while (!file.eof())

\n\n

هذا هو أكثر فخ شائع للمبتدئين. يبدو منطقيًا: "طالما ليس نهاية الملف — اقرأ". لكن المشكلة تكمن في التالي:

\n\n
    \n
  • eof() ترجع true فقط بعد محاولة قراءة فاشلة.
  • \n
  • سيتم تنفيذ الحلقة مرة واحدة أكثر من اللازم.
  • \n
  • سيتم معالجة السطر الأخير مرتين أو ستحصل على بيانات غير صالحة.
  • \n
\n\n

مثال كارثي:

\n\n
std::ifstream file("data.txt");\nstd::string line;\n\nwhile (!file.eof()) {  // لا تفعل هذا أبدًا!\n    std::getline(file, line);\n    std::cout << line << std::endl;  // سيتم طباعة السطر الأخير مرتين\n}
\n\n

الحل الصحيح: استخدم std::getline في شرط الحلقة، كما في المثال الأول. فهو يُرجع التدفق نفسه، الذي يتحول إلى bool: true إذا كانت القراءة ناجحة، و false عند حدوث خطأ أو نهاية الملف.

\n\n

الخطأ رقم 2: تجاهل التحقق من فتح الملف

\n\n

يبدو واضحًا، لكن آلاف الأسطر من الكود على GitHub تتعطل بسبب segmentation fault لهذا السبب. إذا كان الملف غير موجود أو لا توجد صلاحيات للقراءة، فإن ifstream لن يرمي استثناءً — بل سيكون في حالة "تالفة".

\n\n

غير صحيح:

\n\n
std::ifstream file("nonexistent.txt");\nstd::string line;\nwhile (std::getline(file, line)) {  // أوبس! الملف لم يُفتح\n    // هذا الكود لن يتم تنفيذه أبدًا\n}
\n\n

المشكلة هي أنك لن تعرف بوجود خطأ. ستكون البيانات فارغة، وسينهار منطق البرنامج.

\n\n

صحيح:

\n\n
std::ifstream file("data.txt");\nif (!file) {\n    std::cerr << "فشل فتح الملف!" << std::endl;\n    return 1;\n}\n// ثم القراءة
\n\n

استخدم if (!file) أو if (!file.is_open()) — لا فرق، كلاهما يتحقق من حالة التدفق.

\n\n

الخطأ رقم 3: نسيان المسافات والفواصل

\n\n

عامل >> (الاستخراج) يقرأ حتى أول مسافة. إذا استخدمته بدلاً من std::getline، فإنك تخاطر بالحصول على ما لا تتوقعه.

\n\n

مثال: الملف يحتوي على السطر "Hello World".

\n\n
std::string word;\nfile >> word;  // سيقرأ فقط "Hello"\n// word == "Hello"

المدونات

توصيات الكتب