الفصل الثامن: التعامل مع الملفات (File Handling)
مقدمة الفصل
حتى هذه اللحظة، كل البيانات التي تعاملنا معها في برامجنا (مثل قيم المتغيرات أو عناصر القوائم) كانت تُخزّن في ذاكرة الحاسوب المؤقتة (RAM). هذا يعني أنها تُفقد تمامًا بمجرد إغلاق البرنامج.
لكن ماذا لو أردنا حفظ هذه البيانات بشكل دائم؟ ماذا لو أردنا أن يتذكر برنامجنا المهام التي أضافها المستخدم بالأمس، أو حفظ إعدادات معينة؟ هنا يأتي دور التعامل مع الملفات (File Handling).
في هذا الفصل، سنتعلم كيفية جعل برامجنا تقوم بـ:
- قراءة البيانات من ملفات نصية موجودة على القرص الصلب.
- كتابة بيانات جديدة إلى ملفات.
- تعديل محتوى الملفات عبر إضافة بيانات جديدة إليها.
هذه المهارة أساسية لبناء أي تطبيق حقيقي يتجاوز كونه مجرد برنامج مؤقت.
1. فتح الملفات: بوابة التعامل مع البيانات
الخطوة الأولى دائمًا هي فتح الملف الذي نريد التعامل معه. نستخدم لهذا الغرض دالة بايثون المدمجة open
. عند استدعاء هذه الدالة، يجب أن نحدد شيئين أساسيين: اسم الملف، والوضع (mode) الذي نريد أن نفتح به الملف.
أهم أوضاع فتح الملفات:
الوضع | اسم الوضع | الوصف |
---|---|---|
'r' |
Read (قراءة) | يفتح الملف للقراءة فقط. هذا هو الوضع الافتراضي. يسبب خطأ إذا كان الملف غير موجود. |
'w' |
Write (كتابة) | يفتح الملف للكتابة. إذا كان الملف موجودًا، سيتم مسح محتواه بالكامل. إذا لم يكن موجودًا، سيقوم بإنشائه. |
'a' |
Append (إضافة) | يفتح الملف لإضافة بيانات جديدة في نهايته. لا يقوم بمسح المحتوى الحالي. إذا لم يكن موجودًا، سيقوم بإنشائه. |
2. الكتابة في ملف ('w'
)
لنبدأ بأول عملية، وهي كتابة بعض البيانات في ملف جديد.
# Create a file object by opening a file in write mode ('w')
# سيقوم بإنشاء الملف 'greeting.txt' إذا لم يكن موجودًا
file = open("greeting.txt", "w")
# Write a string to the file
file.write("Hello from Python!") # كتابة السطر الأول
# Write another string on a new line
file.write("\nThis is the second line.") # \n لإضافة سطر جديد
# It's crucial to close the file to save the changes
file.close() # إغلاق الملف لحفظ التغييرات
شرح الكود بالتفصيل:
file = open("greeting.txt", "w")
: هنا نطلب من بايثون فتح (أو إنشاء) ملف اسمهgreeting.txt
في وضع الكتابة'w'
. الناتج من هذه العملية هو “كائن ملف” (file object)، قمنا بتخزينه في المتغيرfile
. هذا الكائن هو الذي نستخدمه للتفاعل مع الملف.file.write(...)
: نستخدم دالةwrite
التابعة لكائن الملف لكتابة النصوص. في السطر الثاني من الكتابة، استخدمنا\n
، وهو رمز خاص يعني “سطر جديد” (newline)، لضمان أن النص التالي سيأتي في سطر منفصل.file.close()
: هذه الخطوة ضرورية جدًا. عند الكتابة في ملف، قد لا يتم حفظ البيانات على القرص الصلب فورًا، بل تبقى في ذاكرة مؤقتة. إغلاق الملف يضمن أن كل التغييرات تم حفظها بشكل كامل، كما أنه يحرر الملف ليتمكن نظام التشغيل من استخدامه في مكان آخر.
3. الطريقة الأفضل للتعامل مع الملفات: with
تذكر إغلاق الملف يدويًا في كل مرة قد يكون أمرًا مرهقًا وعرضة للنسيان، مما قد يسبب مشاكل في برنامجك. لحسن الحظ، توفر بايثون طريقة أفضل وأكثر أمانًا تضمن إغلاق الملف تلقائيًا، وهي باستخدام جملة with
.
# The 'with' statement ensures the file is automatically closed
with open("safer_greeting.txt", "w", encoding="utf-8") as f:
# 'f' is now the file object
f.write("مرحبًا من بايثون!\n") # كتابة نص باللغة العربية
f.write("هذه هي الطريقة الآمنة لكتابة الملفات.")
# No need to call f.close(), Python handles it automatically
# لا داعي لاستدعاء دالة الإغلاق، بايثون تتكفل بذلك
شرح الكود بالتفصيل:
with open(...) as f:
: هذه هي البنية الأساسية. جملةwith
تقوم بإنشاء “سياق” (context). كل الكود الذي يأتي داخل هذه الكتلة (بمسافة بادئة) يمكنه استخدام كائن الملف الذي تم تخزينه في المتغيرf
(يمكنك اختيار أي اسم).encoding="utf-8"
: هذا جزء مهم جدًا، خاصة عند التعامل مع نصوص غير إنجليزية مثل اللغة العربية.utf-8
هو معيار ترميز عالمي يسمح بتخزين وعرض جميع الأحرف والرموز من مختلف اللغات بشكل صحيح. اعتد دائمًا على إضافةencoding="utf-8"
عند التعامل مع الملفات النصية لتجنب أي مشاكل مستقبلية.- بمجرد انتهاء كتلة
with
(أي عند الخروج من المسافة البادئة)، يقوم بايثون تلقائيًا بإغلاق الملف، حتى لو حدث خطأ داخل الكتلة. هذا يجعل كودك أكثر موثوقية وأمانًا.
4. القراءة من ملف ('r'
)
الآن بعد أن تعلمنا كيفية الكتابة، لنتعلم كيفية قراءة محتوى ملف موجود.
# Open the file we just created in read mode ('r')
try:
with open("safer_greeting.txt", "r", encoding="utf-8") as file:
# 1. Read the entire content of the file into a single string
content = file.read() # قراءة محتوى الملف بالكامل
print("--- Reading entire file: ---")
print(content) # طباعة المحتوى الكامل
# To read line by line, you can iterate over the file object
# لقراءة الملف سطرًا بسطر، يمكنك التكرار على كائن الملف
print("\n--- Reading line by line: ---")
with open("safer_greeting.txt", "r", encoding="utf-8") as file:
for line in file:
print(f"Line: {line.strip()}") # استخدام strip لإزالة أي أسطر فارغة إضافية
except FileNotFoundError:
print("Error: The file was not found.") # معالجة خطأ في حال عدم وجود الملف
شرح الكود بالتفصيل:
try...except FileNotFoundError
: لقد قمنا بوضع كود القراءة داخل كتلةtry
لمعالجة خطأ شائع وهوFileNotFoundError
. إذا لم يكن الملف موجودًا، سيقوم البرنامج بطباعة رسالة خطأ واضحة بدلاً من التوقف عن العمل.file.read()
: هذه الدالة تقرأ محتوى الملف بالكامل من البداية إلى النهاية وتعيده كنص واحد (string). هذا مناسب للملفات الصغيرة.for line in file:
: هذه هي الطريقة الأكثر كفاءة لقراءة الملفات الكبيرة. بدلاً من تحميل الملف بأكمله في الذاكرة، تقوم حلقةfor
بقراءة الملف سطرًا بسطر، مما يستهلك ذاكرة أقل بكثير.line.strip()
: عند القراءة سطرًا بسطر، كل سطر ينتهي برمز السطر الجديد\n
. دالةstrip
تقوم بإزالة أي مسافات فارغة (بما في ذلك\n
) من بداية ونهاية النص، مما يجعل الطباعة أكثر نظافة.
5. الإضافة إلى ملف ('a'
)
إذا أردت إضافة بيانات جديدة إلى ملف دون مسح محتواه الحالي، استخدم وضع الإضافة 'a'
.
# Open the file in append mode ('a')
with open("log.txt", "a", encoding="utf-8") as log_file:
log_file.write("System check passed at 10:00 AM.\n") # إضافة السجل الأول
log_file.write("User 'Ahmed' logged in.\n") # إضافة السجل الثاني
شرح الكود بالتفصيل:
إذا كان ملف log.txt
موجودًا، فسيتم إضافة هذين السطرين في نهايته. إذا قمت بتشغيل هذا الكود مرة أخرى، فستتم إضافة السطرين مرة أخرى، مما يجعله مثاليًا لملفات السجل (log files) التي تسجل الأحداث بمرور الوقت.
6. تمرين تطبيقي: دفتر ملاحظات بسيط
المطلوب:
كتابة برنامج بسيط يسمح للمستخدم بتدوين ملاحظاته وحفظها في ملف. كل ملاحظة جديدة يجب أن تُضاف إلى نهاية الملف دون حذف الملاحظات السابقة.
إرشادات الحل:
- اطلب من المستخدم إدخال ملاحظته: استخدم دالة
input
للحصول على نص الملاحظة من المستخدم وخزّنها في متغير. - افتح ملف الملاحظات: استخدم بنية
with open
لفتح ملف (ليكن اسمهnotes.txt
) في وضع الإضافة'a'
مع ترميز'utf-8'
. - اكتب الملاحظة في الملف: استخدم دالة
write
لكتابة الملاحظة التي أدخلها المستخدم. لا تنسَ إضافة رمز السطر الجديد\n
في النهاية لكي تبدأ الملاحظة التالية على سطر جديد. - أخبر المستخدم بنجاح العملية: اطبع رسالة تأكيد للمستخدم تفيد بأن ملاحظته قد تم حفظها.
الحل المقترح خطوة بخطوة:
الخطوة 1: الحصول على مدخلات المستخدم
# Ask the user to enter their note
# اطلب من المستخدم إدخال ملاحظته
note_text = input("Please enter your note: ")
شرح الخطوة 1:
هذا السطر بسيط ومباشر. نستخدم دالة input
لعرض رسالة للمستخدم، ثم ننتظر منه كتابة ملاحظته. النص الذي يكتبه المستخدم يتم تخزينه في المتغير note_text
.
الخطوة 2: فتح الملف والكتابة فيه
# Open the file in append mode ('a') to add the new note
# نفتح الملف في وضع الإضافة 'a' لإضافة الملاحظة الجديدة
# Using 'utf-8' encoding is important for Arabic text
# استخدام ترميز 'utf-8' مهم للنصوص العربية
with open("notes.txt", "a", encoding="utf-8") as f:
# Write the user's note, followed by a newline character
# نكتب ملاحظة المستخدم، متبوعة برمز سطر جديد
f.write(note_text + "\n")
شرح الخطوة 2: هنا يكمن جوهر التمرين.
- نستخدم
with open
لضمان أن الملف سيُغلق تلقائيًا. - اسم الملف هو
"notes.txt"
. - الوضع
'a'
(append) يعني أننا سنضيف إلى نهاية الملف. إذا لم يكن الملف موجودًا، سيتم إنشاؤه تلقائيًا في المرة الأولى. encoding="utf-8"
يضمن دعم اللغة العربية.f.write(note_text + "\n")
تقوم بكتابة الملاحظة التي أدخلها المستخدم، ونقوم بإلحاق\n
بها للتأكد من أن كل ملاحظة مستقبلية ستبدأ على سطرها الخاص.
الخطوة 3: طباعة رسالة تأكيد
# Print a confirmation message to the user
# نطبع رسالة تأكيد للمستخدم
print("Your note has been saved successfully!")
شرح الخطوة 3: دائمًا من الجيد إعطاء المستخدم تغذية راجعة (feedback) لتأكيد أن العملية التي طلبها قد تمت بنجاح.
الكود الكامل المجمع:
# --- Simple Note-Taking Program ---
# 1. Ask the user to enter their note
# 1. اطلب من المستخدم إدخال ملاحظته
note_text = input("Please enter your note: ")
# 2. Open the file in append mode ('a') and write the note
# 2. نفتح الملف في وضع الإضافة 'a' ونكتب الملاحظة
try:
with open("notes.txt", "a", encoding="utf-8") as f:
# Write the user's note, followed by a newline character
# نكتب ملاحظة المستخدم، متبوعة برمز سطر جديد
f.write(note_text + "\n")
# 3. Print a confirmation message to the user
# 3. نطبع رسالة تأكيد للمستخدم
print("Your note has been saved successfully!")
except Exception as e:
# Handle potential errors during file operation
# معالجة الأخطاء المحتملة أثناء التعامل مع الملف
print(f"An error occurred: {e}")
7. خلاصة الفصل
- التعامل مع الملفات يسمح لبرامجك بحفظ واسترجاع البيانات بشكل دائم.
- استخدم دائمًا بنية
with open
لأنها الطريقة الأكثر أمانًا وموثوقية. - تذكر تحديد وضع الفتح المناسب:
'r'
للقراءة،'w'
للكتابة (مع مسح المحتوى)، و'a'
للإضافة. - لا تنسَ أبدًا استخدام
encoding="utf-8"
عند التعامل مع نصوص باللغة العربية أو أي لغات أخرى.
ماذا بعد؟
في بعض الأحيان، أثناء تنفيذ البرنامج (مثل التعامل مع الملفات)، قد تحدث أخطاء غير متوقعة. في الفصل التاسع، سنتعلم كيفية معالجة الأخطاء والاستثناءات (Exception Handling) لجعل برامجنا أكثر قوة وقدرة على مواجهة المشاكل دون أن تتوقف عن العمل.