python 101 التعامل مع الملفات النصية في بايثون


عبدالهادي الديوري

تعلمنا إلى الآن مُعظم أساسيات لغة بايثون، تعلمنا كيفية التعامل مع أنواع البيانات المُختلفة، الحصول على مُدخلات من المُستخدم، التعابير الشرطية، حلقات التكرار واستعمال الدوال في برنامجنا لمرونة أكثر. وسنتعلم اليوم كيفيّة التعامل مع الملفات النّصية في لغة بايثون، كيفية الكتابة على ملف، وكيفية قراءة مُحتويات ملف مُعيّن.

python-files-io.png

ما معنى Files I/O؟

ترجمة File هي "ملف" أما I/O فهو اختصار لـكلمتي Input و Output اللتان تعنيان المُدخل والمُخرج على التوالي. تعرفنا إلى الآن على دالتين للقيام بهاتين العمليتين الأولى هي الدالة print للإخراج والدالة raw_input للإدخال. لكنّ هذه الدوال لا تعمل إلا أثناء تشغيل البرنامج، فبعد انتهاء تنفيذه سيعود كل شيء إلى طبيعته وستفقد البيانات التي طبعتها أو التي حصلت عليها من المُستخدم. ماذا لو أردت أن تحتفظ بالبيانات في ملف ما؟ هذا بالضبط ما سنتعلمه اليوم. وإليك مُخطّطا لهذا الدرس:

  • فتح ملف في لغة بايثون.
  • أنماط الوصول Access modes.
  • الكتابة على الملف.
  • قراءة الملف.
  • الدوال المُساعدة عند فتح ملف.
  • إغلاق الملف.

الجملة format

سأستعمل في هذا الدّرس جملة جديدة لم يسبق لنا أن تحدّثنا عنها في الدروس السابقة وهي جملة format التي تُعتبر بمثابة مُحوّل لأنواع القيم المُختلفة إلى قيمة نصيّة، وتُساعد على دمج أي نوع داخل سلسلة نصّية دون الحاجة إلى تحويله بالدالة str. انظر المثال التالي:

>>> '{0}, {1}, {2}'.format('a', 'b', 'c')
'a, b, c'

يُمكن تبسيط الشيفرة أعلاه لتكون كالتّالي:

>>> '{}, {}, {}'.format('a', 'b', 'c')

إليك مثالا لطريقة الاستفادة منها في الواقع:

>>> print 'Hello {} : {} : {} : {}'.format('Abdelhadi', 4, 22.4, True)

Hello Abdelhadi : 4 : 22.4 : True

لاحظ أنّ المُعاملات المُمرّرة للدالة قد أخذت مكان العلامات {} رغم أنّ كلّ قيمة ذات نوع مُختلف عن الأخرى. الطّريقة أعلاه أفضل بكثير من الطّريقة التّقليدية:

>>> print 'Hello', 'Abdelhadi', ':', str(4), ':', str(22.4), ':', str(True)

Hello Abdelhadi : 4 : 22.4 : True

ويُمكنك أيضا أن تؤدي أغراضا أخرى بهذه الجملة، مثلا يُمكنك أن توزع سلسلة نصيّة على أماكن مُعيّنة في السّلسلة كالتالي:

>>> '{0}, {1}, {2}'.format(*'abc')
'a, b, c'

تستطيع تغيير ترتيب العناصر ببساطة:

>>> '{2}, {1}, {0}'.format(*'abc')
'c, b, a'

ويُمكنك أيضا أن تدمج عناصر القواميس في السلاسل النّصيّة بسهولة وذلك بالطّريقة التالية:

>>> table = {'Abdelhadi': 1929, 'Ahmed': 1222, 'Omar': 1320}
>>> print 'Ahmed: {Ahmed:d}; Abdelhadi: {Abdelhadi:d}; Omar: {Omar:d}'.format(**table)
Ahmed: 1222; Abdelhadi: 1929; Omar: 1320

لاحظ النّجمتين ** قبل الاسم table.

فتح ملف في لغة بايثون

قبل أن نتعامل مع أي ملف يجب علينا أولا أن نفتحه، تماما كما تفتح أي ملف نصي للتعديل عليه بمُحرّر النّصوص. لكننا في هذا الدرس سنستعمل لغة بايثون للقيام بذلك. وتوفر لغة بايثون دالة open لفتح الملفات، والتي يُمكنك أن تستخدمها بالشكل التالي:

open('filename.txt', 'Access mode')

المعامل الأول

المُعامل الأول هو اسم الملف، لاحظ أنّك تستطيع استبدال filename بأي اسم تريده ويُمكنك حتى أن تستبدل الامتداد، فمثلا يُمكنك أن تستعمل امتداد ملفات بايثون py بحيث تُصبح الدالة كالتالي:

open('python_file.py', 'Access mode')

الملف يجب أن يكون في مُجلّد العمل، إذا كنت تستعمل نظام GNU/Linux أو نظام Mac وفتحت مُفسر بايثون أو نفّذت ملفا بامتداد py فالملف يجب أن يكون في المجلد الذي قمت بالعملية منه (في الغالب يكون مجلّد المنزل home). أما إذا كنت تستخدم مُفسر لغة بايثون على نظام Windows فسيكون الملف داخل مجلّد تنصيب حزمة Python والذي غالبا ما يكون في القرص C ومجلد باسم PythonNN مع استبدال NN برقم الإصدار الخاص بلغة بايثون، فمثلا لو قمت بتنصيب الإصدار 2.7 فسيكون مسار المُجلد التالي:

C:\Python27

إذا واجهت مشاكل في إيجاد مجلّد العمل يُمكنك تنفيذ الشيفرة التالية للحصول على مسار المُجلّد:

>>> import os
>>> os.getcwd()

المُخرجات ستكون كالتالي (حسب نظام التّشغيل واسم المُستخدم لديك):

'/home/dyouri'

يُمكنك حفظ المُخرج في مُتغير إذا أردت ذلك. ولا تقلق إذا لم تفهم الأسطر السابقة، إذ سنتحدّث عنها في درس لاحق.

المعامل الثاني

بالنّسبة للمعامل الثاني (Access mode ) فهو نمط الوصول الذي ترغب بفتح الملف به وهو إما للكتابة أو للقراءة أو كليهما. انظر الفقرة التالية.

أنماط الوصول Access modes

عند فتح ملف في لغة بايثون، تكون مطالبا بتوفير معاملين للدالة open المُعامل الأول هو اسم الملف، والمعامل الثاني هو نمط الوصول، أي السبب الذي فتحت الملف من أجله، وهناك العديد من الخيارات لذلك، وإليك أهم الخيارات التي يجب عليك أخذها بعين الاعتبار حسب هدفك من فتح الملف:

فتح الملف للقراءة

  • r: هذا هو النمط الافتراضي إذا لم تحدد المُعامل الثاني في دالة open ويُمكنك من قراءة ملف بأحد الدوال المُتاحة لذلك (انظر فصل قراءة الملف). 

مثال:

open('file.txt', 'r')
  • r+: يُفتح الملف في هذا النمط للقراءة والكتابة معا، مع وضع مؤشّر الفأرة في بداية الملف. 

مثال:

open('file.txt', 'r+')

فتح الملف للكتابة

  • w: يُفتح الملف فقط للكتابة، إذا كان الملف موجودا فإنّه يكتب عليه (Overwrite) أي أنّك ستفقد البيانات الأصلية. إذا لم يكن الملف موجودا فإنّ الدالة تنشئ ملفا جديدا للكتابة. 

مثال:

open('file.txt', 'w')
  • w+: فتح الملف لكل من الكتابة والقراءة، إذا كان الملف موجودا فستتم الكتابة عليه (Overwrite). إذا لم يكن الملف موجودا فإنّ الدالة تنشئ ملفا جديدا للكتابة والقراءة. 

مثال:

open('file.txt', 'w+')
  • a: إذا كان الملف موجودا أصلا، فسيُفتح للإلحاق Appending، أي أنّ مُكونات الملف تبقى كما هي، إذا أضفت أي نصّ فسيُضاف في آخر الملف. إذا لم يكن الملف موجودا فسيتم إنشاء ملف جديد. 

مثال:

open('file.txt', 'a')
  • a+: إذا كان الملف موجودا فإنّه يُفتح لكل من الإلحاق والقراءة، إذا لم يكن موجودا فسيتم إنشاء ملف جديد.

مثال:

open('file.txt', 'a+')

الكتابة على الملف

بعد فتح الملف سواء أكان موجودا من قبل أو أنّك أنشأته بالدالة نفسها، ستستطيع الكتابة على الملف وإضافة نصوصك الخاصّة، وذلك بالدالة write مع مُعامل عبارة عن سلسلة نصية، انظر المثال التالي:

>>> file = open('file.txt', 'w') # فتح الملف وإسناده إلى مُتغير
>>> file.write('Hello World!') # الكتابة بالملف
>>> file.close() # إغلاق الملف

ملاحظة: إذا كنت تستعمل المُفسّر، فلحفظ التعديلات عليك الخروج من المفسّر أو إغلاق الملف والذي يُمكنك القيام به بالدالة close، مع ملاحظة أنّك لن تتمكن من تعديل الملف بعد إغلاقه، أي أنّك ستحتاج إلى فتحه من جديد بالدالة open.

لن تُلاحظ أي مُخرجات عند تنفيذك لأي أمر أعلاه، ولكن رغم ذلك فإنّك إذا فتحت الملف file.txt بأي مُحرّر للنّصوص (Notepad مثلا)، فإنّك ستُلاحظ الجملة !Hello World في بداية الملف.

لاحظ بأنّنا فتحنا الملف بنمط الكتابة فقط (w)، إذا فتحت الملف بنفس النّمط مُجدّدا فإنّ التغييرات التي ستكتبها ستُغطّي محتويات الملف. أي أنّك إذا نفّذت الأوامر التاليّة فإنّ مُحتويات الملف ستُصبح الجملة !Hello Python عوضا عن جملة !Hello World

# -*- coding: utf-8 -*-
>>> file = open('file.txt', 'w') # فتح الملف وإسناده إلى مُتغير
>>> file.write('Hello Python!') # الكتابة بالملف
>>> file.close() # إغلاق الملف

يُمكنك إضافة أكثر من مُدخل في كلّ مرّة، المهم أن تكتب على الملف قبل إغلاقه:

>>> file = open('file.txt', 'w')
>>> file.write('Abdelhadi Dyouri!')
>>> file.write('Hsoub Academy!')
>>> file.close()

بعد تنفيذ الشيفرة أعلاه، ستكون مُحتويات الملف كالتالي:

Abdelhadi Dyouri!Hsoub Academy!

لاحظ بأنّ لغة بايثون لا يعود إلى سطر جديد في كل مرة، ولكي تحلّ هذه المسألة فيُمكنك ببساطة إضافة الرّمز n\ بين كل سطر، انظر المثال التّالي:

>>> file = open('file.txt', 'w')
>>> file.write('Abdelhadi Dyouri!\nHsoub Academy!')
>>> file.close()

مُحتويات الملفّ بعد تقسيم الأسطر بالرّمز n\ هي كالتالي:

Abdelhadi Dyouri!
Hsoub Academy!

لاحظ بأنّ الشيفرة أعلاه لها نفس تأثير ما يلي:

>>> file = open('file.txt', 'w')
>>> file.write('Abdelhadi Dyouri!\n')
>>> file.write('Hsoub Academy!')
>>> file.close()

كلّ ما تعلمناه إلى الآن هو كيفية إعادة كتابة الملف، ولكن ماذا لو أردت أن تُبقي على محتويات الملف وترغب بإضافة نصوص له؟ يُمكنك ذلك عن طريق تغيير نمط الوصول إلى نمط الإلحاق عوضا عن نمط الكتابة، لنضف المزيد من النّصوص إلى الملف السابق، إلى الآن مُحتوياته هي كالتالي:

Abdelhadi Dyouri!
Hsoub Academy!

لنضف أقسام الأكاديمية إلى آخر الملف، انظر المثال التالي:

>>> file = open('file.txt', 'a')
>>> file.write('\nFreelance\nEntrepreneurship\nDesign\nApps\nCertificates\nDevops\nMarketing')
>>> file.close()

لاحظ تغيير المُعامل الثاني في دالة open من w إلى a

بعد تنفيذ الشيفرة أعلاه ستكون مُحتويات الملفّ كالتالي:

Abdelhadi Dyouri!
Hsoub Academy!
Freelance
Entrepreneurship
Design
Apps
Certificates
Devops
Marketing

لنُطبّق ما تعلمناه في الدّروس السابقة ولنضع لكلّ قسم عنوان Url الخاص به: 

افتح ملفا باسم links.py وضع فيه ما يلي:

links = []
list = '\nFreelance\nEntrepreneurship\nDesign\nApps\nCertificates\nDevops\nMarketing'

list = list.lower().split('\n')

for item in list:
    list = item.replace(item , 'https://academy.hsoub.com/{}'.format(item))
    links.append(list)

file = open('file.txt', 'w')
file.write('Academy: {}'.format(links[0]))
file.write('\nFreelance: {}'.format(links[1]))
file.write('\nEntrepreneurship: {}'.format(links[2]))
file.write('\nDesign: {}'.format(links[3]))
file.write('\nApps: {}'.format(links[4]))
file.write('\nCertificates: {}'.format(links[5]))
file.write('\nDevops: {}'.format(links[6]))
file.write('\nMarketing: {}'.format(links[7]))
file.close()

أولا عرّفنا قائمة روابط فارغة باسم links بعدها أسندنا الأقسام إلى مُتغيّر باسم list ثمّ حولنا الأحرف إلى أحرف صغيرة و قسّمنا السّلسلة النّصية، بعدها استعملنا الحلقة for للدوران على عناصر القائمة، وفي كلّ مرّة نستبدل قيمة القسم برابطه ونُلحق العنصر النّاتج إلى القائمة links وبعدها فتحنا الملف ووضعنا لكل قسم رابطه الخاص وأخيرا أغلقنا الملف.

بعد تنفيذ الشيفرة أعلاه ستكون مُحتويات الملف file.txt كالتالي:

Academy: https://academy.hsoub.com/
Freelance: https://academy.hsoub.com/freelance
Entrepreneurship: https://academy.hsoub.com/entrepreneurship
Design: https://academy.hsoub.com/design
Apps: https://academy.hsoub.com/apps
Certificates: https://academy.hsoub.com/certificates
Devops: https://academy.hsoub.com/devops
Marketing: https://academy.hsoub.com/marketing

يُمكنك أن تجعل البرنامج أكثر ذكاء وذلك باستبدال قائمة الأقسام بمُدخل من المُستخدم وتُضيف رابط القسم إلى الملف، على سبيل المثال سيعمل البرنامج كالتالي:

Enter the name of the category: 

مثلا لنُدخل programming للحصول على رابط قسم البرمجة، يجب أن تكون المُخرجات شيئا كالتالي:

Enter the name of the category: programming

Ok! Added https://academy.hsoub.com/programming to file.txt

هل رأيت حلاوة البرمجة؟ تذكّر بأنّ خيالك هو حدود ما تستطيع القيام به.

قراءة الملف

الدالة read

بعد الكتابة على الملف سيتوجّب علينا قراءته، كما الكتابة تُوفّر لنا لغة بايثون دالة خاصة بالقراءة وهي الدالة read التي يُمكننا أن نستعملها كالتالي:

file = open('file.txt', 'r')
file.read()

لاحظ أنّنا غيّرنا المُعامل الثاني من w إلى r وذلك لأنّنا نرغب بفتح الملفّ للقراءة. 

بعد تنفيذ الشيفرة أعلاه ستكون المُخرجات كالتالي:

'Academy: https://academy.hsoub.com/\nFreelance: https://academy.hsoub.com/freelance\nEntrepreneurship: https://academy.hsoub.com/entrepreneurship\nDesign: https://academy.hsoub.com/design\nApps: https://academy.hsoub.com/apps\nCertificates: https://academy.hsoub.com/certificates\nDevops: https://academy.hsoub.com/devops\nMarketing: https://academy.hsoub.com/marketing\n'

إذا عاودت تنفيذ الدالة read من جديد فإنّ المُخرج سيكون سلسلة نصيّة فارغة'' وهذا يدلّ على أنّنا وصلنا إلى نهاية الملفّ، ولكي تعود إلى بداية الملف من جديد فعليك فتحه مُجدّدا بالدالة open.

كما تُلاحظ فإنّ المُخرجات لا تبدو جميلة أبدا، يُمكنك أن تقرأ أسطر الملف باستخدام جملة for عوضا عن الدالة read وستكون المُخرجات نظيفة هذه المرّة.

file = open('file.txt', 'r')

for line in file:
    print line

ستكون المُخرجات كالتالي:

Academy: https://academy.hsoub.com/

Freelance: https://academy.hsoub.com/freelance

Entrepreneurship: https://academy.hsoub.com/entrepreneurship

Design: https://academy.hsoub.com/design

Apps: https://academy.hsoub.com/apps

Certificates: https://academy.hsoub.com/certificates

Devops: https://academy.hsoub.com/devops

Marketing: https://academy.hsoub.com/marketing

يُمكنك أيضا تحديد كم من بايت Byte ترغب بقراءته من بداية الملف. فمثلا إذا كنت ترغب بقراءة أول 8 بايت من مُحتويات الملف، فيُمكنك تمرير العدد 8 إلى الدالة read كمُعامل:

>>> file = open('file.txt', 'r')
>>> file.read(8)
'Academy:'
>>> file.close()

المُخرجات ستكون كالتالي (أول 8 أحرف من الملف):

'Academy:'

لاحظ بأنّ البايت الواحد لا يعني دائما الحرف الواحد إذ أنّ هناك استثناءات عديدة، فمثلا في اللغة العربية الحرف الواحد يشغل حوالي 2 بايت أما الأحرف الصينية فتشغل حوالي 3 بايت. في الأحرف الإنجليزية عادة ما يُساوي الحرف الواحد 1 بايت فقط.

الدالة readline

يُمكنك أن تقرأ سطرا واحدا من الملف في كلّ مرّة، وذلك بالاعتماد على جُملة readline عوضا عن جملة read.

>>> file = open('file.txt', 'r')
>>> file.readline()

'Academy: https://academy.hsoub.com/\n'

>>> file.readline()

'Freelance: https://academy.hsoub.com/freelance\n'

>>> file.readline()

'Entrepreneurship: https://academy.hsoub.com/entrepreneurship\n'

لاحظ بأنّ المُخرج يكون مُختلفا في كلّ مرّة تُستَدعَى فيها الدالة readline إذ أنّ المُخرج يكون سطرا واحدا في كل مرة، وفي المرّة التالية تكون النّتيجة السّطر التالي إلى نهاية الملفّ. في النّهاية سيكون المخرج سلسلة نصيّة فارغة:

>>> file.readline()

'Marketing: https://academy.hsoub.com/marketing\n'

>>> file.readline()

''

إذا أردت العودة إلى بداية الملفّ من جديد فيُمكنك ذلك إما بإغلاق الملف وفتحه من جديد أو باستعمال الدالةّ seek مع تمرير عدد البايتات الذي ترغب بتخطّيه، (أي صفرا للعودة إلى بداية الملف).

>>> file.readline()

''

>>> file.seek(0)
>>> file.readline()

'Academy: https://academy.hsoub.com/\n'

يُمكن مثلا العودة إلى أول 8 بايت من الملف بالطّريقة التالية:

>>> file.seek(8)
>>> file.readline()

' https://academy.hsoub.com/\n'

يُمكنك أن تعتمد على الدالة tell لتعرف مركز القراءة الحالي.

>>> file.seek(66)
>>> file.tell()
66

تقبل الدّالة readline مُعاملا لتحديد عدد البايتات المرغوب قراءتها (تماما مثل شقيقتها read).

>>> file.seek(0) # للعودة إلى بداية الملف
>>> file.readline(8)
'Academy:'

الدالة readlines

تُعتبر الدالة readlines طريقة أخرى لقراءة الملف، وتُرجع قائمة بجميع الأسطر التي يحتويها الملف:

>>> file = open('file.txt', 'r')
>>> file.readlines()
['Academy: https://academy.hsoub.com/\n', 'Freelance: https://academy.hsoub.com/freelance\n', 'Entrepreneurship: https://academy.hsoub.com/entrepreneurship\n', 'Design: https://academy.hsoub.com/design\n', 'Apps: https://academy.hsoub.com/apps\n', 'Certificates: https://academy.hsoub.com/certificates\n', 'Devops: https://academy.hsoub.com/devops\n', 'Marketing: https://academy.hsoub.com/marketing']

يُمكنك مثلا حساب عدد أسطر ملفّ ما بحساب عدد عناصر القائمة بالدالة len:

>>> file = open('file.txt', 'r')
>>> len(file.readlines())
8

إغلاق الملف

رغم أنّ عمليّة إغلاق الملف ليست ضرورية لحفظ التّغييرات، إلّا أنّ القيام بالأمر منصوح به بشدّة، لذلك يجب عليك أن تتأكّد من أنّ الملفّ قد أُغلق بعد انتهائك من إجراء العمليّات على الملف. لقد تعرّفنا من قبل على كيفيّة إغلاق الملف:

>>> file = open('file.txt')
>>> file.close()

للتحقق من أنّ الملف مُغلق يُمكن أن تستعين بالجملة closed والتي تُرجع قيمة منطقية (إما True أو False). إذا كان الملف مُغلقا فسترجع الجملة True أما إذا لم يكن مغلقا فستُرجع الجملة False.

>>> file = open('file.txt') # فتح الملف
>>> file.closed   # التحقق من أنّ الملف مُغلق
False
>>> file.close()  # إغلاق الملف
>>> file.closed   # التحقق من جديد
True

يُمكن كذلك الاستعانة بالجملة with as لفتح ملف والقيام بعمليات ثم إغلاقه آليا.

with open('file.txt', 'r') as file:
    file.read()

الملف يُغلق ذاتيا بعد انتهاء الجزء المُزاحِ (ذو الإزاحة) من الشيفرة، ويُمكنك التأكّد من الأمر بالجملة closed.

الدوال المساعدة

بعد فتح الملف يُمكنك الحصول على معلومات حول الملف ببعض الدوال المبنية مُسبقا Built-in functions وهي كالتالي:

  • closed: التحقق من ما إذا كان الملف مُغلقا أو لا (انظر الفصل السابق).
  • name: الحصول على اسم الملفّ.
>>> file = open('file.txt')
>>> file.name
'file.txt'
  • mode: الحصول على نمط الوصول.
>>> file = open('file.txt', 'w+')
>>> file.mode
'w+'

تمارين

تمرين 1

اكتب برنامجا للحصول على قيم من المُستخدم وأدخلها إلى ملف نصي.

تمرين 2

صحّح الخطأ في ما يلي:

file = open('file.txt', 'r')
file.write('Hello World!')

تمرين 3

صحّح الخطأ في ما يلي:

file = open('file.txt', 'w')
file.write('Hello World!')
file.close()
file.write('Hello!')

تمرين 4

اكتب برنامج تسجيل الدخول في الدروس السابقة ليقبل ملفّا كقاعدة بيانات. (احفظ اسم المُستخدم وكلمة المرور في الملف عوضا عن الذاكرة.)

المصادر المعتمدة



1 شخص أعجب بهذا


تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن