File I/O والتعامل مع الملفات — C++ المتقدم
الملفات (File I/O)
الملفات في C++ تدفقات (streams) مثل cin و cout تماماً: نفس << و >> و getline. وهي تطبق RAII: الملف يُغلق تلقائياً عند خروج الكائن من النطاق.
| الصنف | الاستخدام |
|---|---|
| ofstream | كتابة |
| ifstream | قراءة |
| fstream | قراءة وكتابة |
| stringstream | تدفق داخل نص (مفيد للتحليل) |
الكتابة
#include <fstream>
#include <iostream>
using namespace std;
int main() {
ofstream out("notes.txt"); // يُنشئ الملف أو يفرّغه
if (!out) { // افحص دائماً
cerr << "تعذر فتح الملف\n";
return 1;
}
out << "السطر الأول\n";
out << "الدرجة: " << 95 << '\n';
} // يُغلق تلقائياً هناأوضاع الفتح
| الوضع | المعنى |
|---|---|
| ios::out | كتابة (الافتراضي لـ ofstream) — يفرّغ الملف |
| ios::app | إضافة إلى النهاية دون حذف |
| ios::in | قراءة |
| ios::binary | ثنائي: بلا تحويل لرموز نهاية السطر |
| ios::trunc | تفريغ صريح |
ofstream log("app.log", ios::app); — لملفات السجل.
القراءة الصحيحة
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
{ ofstream("notes.txt") << "السطر الأول\nالسطر الثاني\n"; } // ملف تجريبي للقراءة
ifstream in("notes.txt");
if (!in) { cerr << "الملف غير موجود\n"; return 1; }
string line;
int n = 0;
while (getline(in, line)) { // ✅ الشرط هو نجاح القراءة نفسها
cout << ++n << ": " << line << '\n';
}
}⚠️ لا تكتب while (!in.eof()): eof لا تصبح true إلا بعد فشل محاولة قراءة، فتعالج السطر الأخير مرتين أو سطراً فارغاً. اجعل القراءة هي الشرط دائماً.
تحليل CSV بـ stringstream
#include <sstream>
#include <string>
#include <vector>
using namespace std;
struct Row { string name; int score; };
bool parseRow(const string& line, Row& out) {
stringstream ss(line);
string scoreText;
if (!getline(ss, out.name, ',') || !getline(ss, scoreText)) return false;
try { out.score = stoi(scoreText); } catch (...) { return false; }
return true;
}
// parseRow("سارة,91", r) → true, r.name == "سارة", r.score == 91getline(ss, field, ',') تقرأ حتى الفاصلة. (CSV الحقيقي قد يحتوي فواصل داخل علامات تنصيص — للمشاريع الجادة استخدم مكتبة.)
الملفات الثنائية
تكتب البايتات كما هي في الذاكرة: أسرع وأصغر، لكنها غير مقروءة للإنسان وغير محمولة بين الأنظمة المختلفة (حجم الأنواع وترتيب البايتات). مناسبة لأنواع بسيطة مثل مصفوفات الأعداد:
#include <fstream>
#include <vector>
using namespace std;
void saveInts(const vector<int>& v) {
ofstream out("data.bin", ios::binary);
out.write(reinterpret_cast<const char*>(v.data()), v.size() * sizeof(int));
}لا تكتب صنفاً فيه string أو مؤشرات بهذه الطريقة — ستكتب عناوين لا المحتوى.
std::filesystem (C++17)
للتعامل مع الملفات نفسها لا محتواها:
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
void info(const fs::path& p) {
if (fs::exists(p)) std::cout << p << " الحجم: " << fs::file_size(p) << " بايت\n";
// أيضاً: fs::create_directories، fs::remove، fs::directory_iterator
}تمرين
اكتب برنامج "دفتر درجات": يقرأ grades.csv (اسم,درجة)، يتجاهل الأسطر غير الصالحة مع طباعة رقمها، ويكتب report.txt فيه المتوسط وأعلى طالب. أضف سطراً في log.txt بوضع الإضافة عند كل تشغيل.
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <iomanip>
using namespace std;
struct Student {
int id;
string name;
double gpa;
string toString() const {
return to_string(id) + "," + name + "," + to_string(gpa);
}
static Student fromString(const string& line) {
Student s;
stringstream ss(line);
string token;
getline(ss, token, ',');
s.id = stoi(token);
getline(ss, s.name, ',');
getline(ss, token, ',');
s.gpa = stod(token);
return s;
}
};
int main() {
// ===== كتابة نص =====
cout << "=== كتابة نص ===" << endl;
{
ofstream file("output.txt");
if (!file.is_open()) {
cerr << "فشل فتح الملف!" << endl;
return 1;
}
file << "مرحباً بالعالم!" << endl;
file << "سطر ثاني" << endl;
file << "عدد: " << 42 << endl;
file.close();
cout << "✅ تم إنشاء output.txt" << endl;
}
// ===== قراءة نص =====
cout << "\n=== قراءة نص ===" << endl;
{
ifstream file("output.txt");
if (file.is_open()) {
string line;
while (getline(file, line)) {
cout << "> " << line << endl;
}
file.close();
}
}
// ===== إضافة للملف =====
cout << "\n=== إضافة ===" << endl;
{
ofstream file("output.txt", ios::app);
file << "سطر جديد مضاف!" << endl;
file.close();
cout << "✅ تم الإضافة" << endl;
}
// ===== CSV =====
cout << "\n=== كتابة CSV ===" << endl;
{
ofstream file("students.csv");
file << "ID,Name,GPA" << endl;
vector<Student> students = {
{1, "أحمد", 3.8},
{2, "سارة", 3.9},
{3, "محمد", 3.5},
{4, "فاطمة", 4.0}
};
for (const auto& s : students) {
file << s.toString() << endl;
}
file.close();
cout << "✅ تم إنشاء students.csv" << endl;
}
// ===== قراءة CSV =====
cout << "\n=== قراءة CSV ===" << endl;
{
ifstream file("students.csv");
string line;
getline(file, line); // تخطي العنوان
vector<Student> loaded;
while (getline(file, line)) {
loaded.push_back(Student::fromString(line));
}
cout << left << setw(5) << "ID"
<< setw(15) << "Name"
<< setw(5) << "GPA" << endl;
cout << string(25, '-') << endl;
for (const auto& s : loaded) {
cout << left << setw(5) << s.id
<< setw(15) << s.name
<< setw(5) << fixed << setprecision(1) << s.gpa << endl;
}
file.close();
}
// ===== ملف ثنائي =====
cout << "\n=== ملف ثنائي ===" << endl;
{
// كتابة
ofstream out("data.bin", ios::binary);
vector<int> numbers = {10, 20, 30, 40, 50};
out.write(reinterpret_cast<char*>(numbers.data()),
numbers.size() * sizeof(int));
out.close();
cout << "✅ تم كتابة " << numbers.size() << " أرقام" << endl;
// قراءة
ifstream in("data.bin", ios::binary);
vector<int> loaded(5);
in.read(reinterpret_cast<char*>(loaded.data()),
loaded.size() * sizeof(int));
in.close();
cout << "الأرقام المقروءة: ";
for (int n : loaded) cout << n << " ";
cout << endl;
}
// ===== التحقق من وجود ملف =====
cout << "\n=== التحقق ===" << endl;
{
ifstream test("nonexistent.txt");
if (test.is_open()) {
cout << "الملف موجود" << endl;
test.close();
} else {
cout << "الملف غير موجود" << endl;
}
}
// ===== stringstream =====
cout << "\n=== stringstream ===" << endl;
{
stringstream ss;
ss << "مرحباً " << 42 << " " << 3.14;
string word;
int num;
double pi;
ss >> word >> num >> pi;
cout << "word: " << word << endl;
cout << "num: " << num << endl;
cout << "pi: " << pi << endl;
}
return 0;
}اختبر فهمك