7. الملفات النصية

7.1. النص البرمجي [fic_01]: قراءة/كتابة ملف نصي
يوضح البرنامج النصي التالي مثالاً على العمل مع الملفات النصية:
ملاحظات:
- السطر 28: يفتح الملف للكتابة (w=write). إذا كان الملف موجودًا بالفعل، فسيتم استبداله؛
- الأسطر 30–34: إنشاء 100 سطر في الملف النصي؛
- السطر 34: لكتابة سطر في الملف النصي. لا تضيف طريقة [write] حرفًا لبدء سطر جديد. لذلك، يجب عليك تضمين هذا الحرف في النص المكتوب؛
- الأسطر 35-37: معالجة أي استثناءات؛
- السطر 37: إيقاف تنفيذ البرنامج النصي (ولكن بعد تنفيذ كتلة finally)؛
- الأسطر 38-41: في جميع الحالات، سواء حدث خطأ أم لا، أغلق الملف إذا كان مفتوحًا؛
- السطر 47: فتح الملف للقراءة (r=read)؛
- السطر 49: تعريف قاموس فارغ؛
- السطر 52: تقرأ طريقة [readline] سطرًا من النص، بما في ذلك حرف نهاية السطر. تقوم طريقة [strip] بإزالة "المسافات" من بداية ونهاية السلسلة. ونقصد بـ "المسافات" أحرف المسافات البيضاء، وفواصل الأسطر، وفواصل الصفحات، وعلامات الجدولة، وبعض العناصر الأخرى. لذا، لن تحتوي [line] هنا على أحرف فاصل الأسطر [\r\n] (Windows) أو [\n] (Unix)؛
- السطر 54: تتم معالجة الملف حتى يتم العثور على سطر فارغ؛
- الأسطر 54–64: يتم نقل الملف النصي إلى القاموس [dico]. المفتاح هو حقل [login]، والقيمة تتكون من الحقول [uid:gid:infos:dir:shell]؛
- الأسطر 65–67: معالجة أي استثناءات؛
- الأسطر 68–71: إغلاق الملف في جميع الحالات، سواء حدث خطأ أم لا؛
- السطران 74-75: الاستعلام عن القاموس [dico]؛
الملف [data/infos.txt]:
إخراج الشاشة:
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fichiers/fic_01.py
login10 : ['uid10', 'gid10', 'infos10', 'dir10', 'shell10']
la clé [X] n'existe pas
Process finished with exit code 0
7.2. البرنامج النصي [fic_02]: التعامل مع الملفات النصية المشفرة بـ UTF-8
في بقية هذا المستند، سنعمل حصريًا مع الملفات النصية المشفرة بـ UTF-8. أولاً، سنقوم بتكوين PyCharm:

- في [5-6]: حدد ترميز UTF-8 لملفات المشروع؛
لإنشاء ملف مشفر بـ UTF-8، اتبع الخطوات التالية (fic-02):
ملاحظات
- السطر 2: للتعامل مع ترميز الملف، نقوم باستيراد الوحدة النمطية [codecs]؛
- السطر 6: تُستخدم طريقة [codecs.open] مثل الدالة القياسية [open]. ومع ذلك، يمكنك تحديد الترميز المطلوب (عند الإنشاء) أو الترميز الموجود (عند القراءة). بعد الفتح، يُستخدم كائن [file] الذي تم الحصول عليه في السطر 6 كملف قياسي؛
- السطر 7: تم استخدام أحرف مشطوبة، والتي عادةً ما يكون لها تمثيلات مختلفة اعتمادًا على ترميز الأحرف المستخدم؛
النتائج
عند فتح ملف [data/utf8.txt] الذي تم الحصول عليه (انظر السطر 6)، يتم الحصول على النتيجة التالية:

7.3. البرنامج النصي [fic_03]: معالجة الملفات النصية المشفرة بـ ISO-8859-1
يقوم البرنامج النصي [fic_03] بنفس ما يقوم به البرنامج النصي [fic_02] ولكنه يقوم بترميز الملف النصي في ISO-8859-1. نريد إظهار الفرق بين الملفات الناتجة:
عندما نفتح ملف [data/iso-8859-1] الذي تم إنشاؤه في السطر السادس، نحصل على النتيجة التالية:

نظرًا لأننا قمنا بتكوين المشروع للعمل مع ملفات UTF-8، حاول PyCharm فتح ملف [iso-8859-1.txt] بتنسيق UTF-8. ويمكنه أن يرى [1] أن الملف ليس بتنسيق UTF-8. ثم يقترح [2] إعادة تحميل الملف بترميز مختلف:

- في [3-5]: يتم إعادة تحميل الملف باستخدام ترميز ISO-8859-1؛

- في [6]، نفس الملف ولكن مع عرضه بترميز مختلف؛
إذا عدنا إلى إعدادات المشروع:

- نرى أنه في [6-7]، لاحظ PyCharm أن الملف [iso-8859-1.txt] يجب فتحه بترميز ISO-8859-1. وهذا يمثل استثناءً للقاعدة [5]؛
7.4. النص البرمجي [json_01]: العمل مع ملف JSON
JSON هي اختصار لـ JavaScript Object Notation. كما يوحي الاسم، فهو تمثيل نصي لكائنات JavaScript. هنا، سنستخدمه مع كائنات Python.
سيبدو ملف JSON الذي يتم إدارته [data/in.json] كما يلي:

- في [2]، يمكننا أن نرى أن المحتوى النصي لملف [in.json] يمكن أن يمثل قاموس Python. قام PyCharm بتنسيق (Ctrl-Alt-L) هذا النص، ولكن حتى لو كان في سطر واحد، فلن يحدث ذلك أي فرق. لا يهم تنسيق النص طالما أنه يمثل كائن Python من الناحية النحوية؛
يوضح البرنامج النصي [json-01] كيفية استخدام هذا الملف:
ملاحظات
- السطر 3: للعمل مع JSON، نقوم باستيراد الوحدة النمطية [json]؛
- السطر 11: سنعمل مع ملفات JSON المشفرة بـ UTF-8. هنا، نفتح الملف [data/in.json] باستخدام وحدة [codecs]؛
- السطر 13: تقرأ طريقة [json.load] محتويات ملف JSON وتخزنها في المتغير [data]. سيكون نوع هذا المتغير عبارة عن قاموس؛
- الأسطر 15–18: للتحقق من أننا حصلنا بالفعل على قاموس Python، نعرض بعض عناصره؛
- السطران 20-21: نقوم بإجراء العملية العكسية: يتم كتابة القاموس [data] إلى ملف مشفر بتنسيق UTF-8 باستخدام طريقة [json.dump]؛
- السطور 22–25: معالجة أي استثناءات؛
- السطور 26-31: في جميع الأحوال، سواء حدث خطأ أم لا، نقوم بإغلاق أي ملفات قد تكون مفتوحة؛
النتائج
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fichiers/json_01.py
data={'limites': [9964, 27519, 73779, 156244, 0], 'coeffR': [0, 0.14, 0.3, 0.41, 0.45], 'coeffN': [0, 1394.96, 5798, 13913.69, 20163.45], 'PLAFOND_QF_DEMI_PART': 1551, 'PLAFOND_REVENUS_CELIBATAIRE_POUR_REDUCTION': 21037, 'PLAFOND_REVENUS_COUPLE_POUR_REDUCTION': 42074, 'VALEUR_REDUC_DEMI_PART': 3797, 'PLAFOND_DECOTE_CELIBATAIRE': 1196, 'PLAFOND_DECOTE_COUPLE': 1970, 'PLAFOND_IMPOT_COUPLE_POUR_DECOTE': 2627, 'PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE': 1595, 'ABATTEMENT_DIXPOURCENT_MAX': 12502, 'ABATTEMENT_DIXPOURCENT_MIN': 437}, type(data)=<class 'dict'>
limites=[9964, 27519, 73779, 156244, 0], type(limites)=<class 'list'>
limites[1]=27519, type(limites[1])=<class 'int'>
Process finished with exit code 0
- تُظهر الأسطر 2–4 أننا نجحنا في استرداد القاموس من ملف JSON؛
الآن، دعونا نلقي نظرة على محتويات ملف [data/out.json]:

النص الموجود في الملف مكتوب في سطر واحد. ومع ذلك، يتعرف PyCharm على ملفات JSON، ويمكننا تنسيقها — تمامًا مثل ملفات Python وغيرها — باستخدام Ctrl-Alt-L. وهذا يعطينا ما يلي:

7.5. نص برمجي [json_02]: التعامل مع ملفات JSON المشفرة بـ UTF-8
يمكن أن يتخذ ملف JSON المشفر بـ UTF-8 شكلين:
- في هذا البرنامج النصي، يتم كتابة قاموس [data] (السطر 7) إلى ملفين JSON (السطران 14 و 17)؛
- السطران 14 و 17: في كلتا الحالتين، يتم إنشاء ملف نصي بتنسيق UTF-8؛
- السطر 15: عند كتابة القاموس، نستخدم المعلمة المسماة [ensure_ascii=True]؛
- السطر 18: عند كتابة القاموس، نستخدم المعلمة المسماة [ensure_ascii=False]؛
فيما يلي الملفان الناتجان:

- في ملف [out1.json]، تم استبدال الأحرف المُشَدَّدة بسلسلة من الأحرف تمثل رمزها الثنائي في UTF-8. ويُشار إلى هذه العملية أحيانًا باسم "الهروب" (escaping). ومن الناحية الفنية، في النسخة الثنائية لملف [out1.json]، يتم تمثيل الحرف é في كلمة [marié] برموز UTF-8 الثنائية لستة أحرف متتالية وهي [\u00e9]؛
- في ملف [out2.json]، تم ترك الأحرف المُشَدَّدة كما هي. وهذا يعني أنه في البيانات الثنائية لـ [out2.json]، يتم تمثيل هذه الأحرف برمزها الثنائي UTF-8 (رمز UTF-8 واحد فقط، بدلاً من 6 في [out1]). بالنسبة للحرف é في [marié]، نجد الرمز الثنائي المكون من 4 بايت [00e9]؛
- إن قيمة المعلمة [ensure_ascii] الخاصة بالطريقة [json.dump] هي التي تحدد التنسيق المستخدم؛
تستخدم بعض التطبيقات UTF-8 "المهرب" لملفات JSON الخاصة بها. في هذه الحالة، يجب استخدام القيمة [ensure_ascii=True]. هذه القيمة هي في الواقع القيمة الافتراضية. لذلك، إذا لم يتم استخدام المعلمة [ensure_ascii]، فسنعمل مع ملفات JSON بتنسيق UTF-8 المهرب.
يستمر البرنامج النصي على النحو التالي:
ملاحظات
- الأسطر 11–34: قراءة الملفين [out1.json، out2.json] وعرض القاموس الذي تمت قراءته في كل حالة؛
النتائج
من المثير للدهشة أننا نرى أنه لم يكن من الضروري تحديد نوع الترميز (مع أو بدون هروب) لسلسلة JSON المراد قراءتها في دالة [json.load] (السطران 17 و22). في كلتا الحالتين، نسترد القاموس الصحيح.