تقييم الموضوع :
  • 0 أصوات - بمعدل 0
  • 1
  • 2
  • 3
  • 4
  • 5
الملفات في بيثون
#1
# الملفات في بيثون

## تذكير

عند التعامل مع السلاسل النصية، من المهم معرفة ترميز المحارف المستخدم في السلسلة النصية سواء لقراءتها او لكتابتها. الترميز القياسي في بيثون3 هو اليونيكود وعادة utf-8، لكن احتمال أن يكون ترميزا آخر وارد أيضا وخاصة اذا كان مصدر السلسلة النصية قديما.



## الدالة open

عند معالجة الملفات، سنحتاج أيضا الى معرفة وحسن إدارة ترميز المحارف في الملفات ، وسنرى أنها عملية بسيطة في الواقع. مثال:

كود :
# open  لانشاء او فتح ملف نستخدم الدالة
f = open('spam.txt', 'w', encoding='utf8')

type(f)                              # فقط لنعرف نوع المتغير
for i in range(10):                  # الكتابة في الملف عبر تعليمة تكرار
   f.write("line {}\n".format(i+1)) # line 1\n line 2\n ... line 10\n
   
f.close()
تقوم الدالة open بفتح ملف في المسار الذي مررناه اليها في الوسيط الاول: ستقوم الدالة بفتح ملف spam.txt في نفس مجلد العمل الحالي، فإن لم يكن موجودا تقوم بانشائه. اخترت ملفا في نفس مجلد العمل للتبسيط. لاحظ أننا مررنا ناتج open الى متغير من نوع file سميناه هنا f.



عبر الوسيط الثاني نحدد الغرض من فتح الملف: للكتابة فقط نستخدم 'w' (سيتم حذف ما في الملف من نص سابق اذا كان موجودا أو يتم انشاء ملف جديد)، وللقراءة فقط نستخدم 'r' ولغرض الكتابة فقط لكن في آخر الملف دون حذف ما فيه من نص سابق نستخدم 'a' مع الملاحظة أنه يوجد غيرها من الخيارات.



الوسيط الثالث نحدد به ترميز المحارف (وهو افتراضيا utf8 اذا لم يتم ذكره).



بعد الكتابة في الملف (هنا عبر كتلة تعليمات التكرار) لا ننسى غلق الملف



بعد تنفيذ السطور السابقة يمكننا أن نلاحظ وجود ملف نصي جديد في مجلد العمل يحمل اسم spam.txt يمكن فتحه بواسطة محرر النصوص العادي، وسنرى الآن كيف نفتحه ونعالج محتواه عبر تعليمات بيثون



كود :
f = open('spam.txt', 'r', encoding='utf8')  # فتح ملف موجود للقراءة
lines = []                                  # قائمة لتخزين سطور الملف
for line in f:                              # تخزين الملف سطرا سطرا
   lines.append(line)                      # لاحظ السهولة

f.close()                                   # غلق الملف
print(lines)                                # طباعة النتيجة
ينتج عن هذه السطور من التعليمات قائمة تحتوي على  عدد عناصر بحسب عدد السطور في الملف. لاحظ رمز نهاية السطر غير المرئي '\n' في كل عنصر. أذا لم نرغب فيه نعوض التعليمة المتكررة كما يلي

كود :
f = open('spam.txt', 'r', encoding='utf8')
lines = []
for line in f:                              # هنا استخدمنا دالة تنظيف النص من رمز نهاية السطر
   lines.append(line.strip())              # line.strip()

f.close()
print(lines)
قد نرغب في فتح ملف لقراءة محتواه ومعالجته ثم حفظ النتيجة في ملف ثان، مثلا:



كود :
f1 = open('spam.txt', 'r', encoding='utf8')     # فتح الملف الاول للقراءة
f2 = open('spam2.txt', 'w', encoding='utf8')    # فتح الملف الثاني للكتابة
for line in f1:
   line = line.split()                         # معالجة كل سطر بتحويله الى قائمة كلمات
   line[0] = line[0].upper()                   # تكبير حروف الكلمة الاولى
   f2.write(",".join(line) + "\n")             # اعادة تحويل عناصر القائمة الى سلسلة نصية
                                               #u في ملف جديد مع استخدام الفاصلة بين الكلمات
   
f1.close()                                      # غلق الملف الاول
f2.close()                                      # غلق الملف الثاني
هذا السكربت يفتح ملفا لقراءته، يعالج السطور عبر تحويلها الى قائمة قوائم مع اعادة كتابة العنصر الاول بحروف كبيرة، ثم يكتب الناتج في ملف ثان بعد اعادة تحويله الى سطور وباستعمل الفاصلة بين الكلمات عوض الفراغ. اذا نظرت في مجلد العمل ستجد الآن ملفا آخر باسم spam2.txt



## معالجة أخطاء الوصول الى الملفات عبر context manager

عند التعامل مع الملفات، لابد من الاخذ في الاعتبار احتمالات الخطأ المتنوعة. بيثون وفر لنا طريقة سهلة يتوجب استخدامها *دائما* للتعامل مع الملفات لكي نتجنب الكثير من الاخطاء المتكررة:

كود :
# a باستخدام `with` نضمن غلق الملف
with open("foo.txt", "w", encoding='utf-8') as myfile:
   for i in range(100,105):
       myfile.write("{}\n".format(i))
لنفتح الملف ثانية لكي نضيف له سطرين آخرين:

كود :
# 'a' نستخدم الخيار
with open("foo.txt", "a", encoding='utf-8') as myfile:
   for i in range(105, 107):
       myfile.write("{}\n".format(i))
ثم نفتحه للمرة الثالثة من أجل قراءة محتواه

كود :
with open("foo.txt", encoding='utf-8') as myfile: # 'r' لاحظ بدون تحديد الخيار فهو افتراضيا قراءة فقط
   for line in myfile:     # يوجد رمز نهاية السطر في كل سطر
       print(line, end='') # print نتجنب نهاية سطر آخر تضيفه افتراضيا الدالة
يوجد خيارات أخرى لفتح ملف:

- فتح ملف قراءة وكتابة باستخدام +

- فتح ملف في وضع ثنائي binary mode باستخدام b

يمكن مراجعة https://docs.python.org/3/library/functions.html#open للمزيد من الاطلاع



## معلومات اضافية:

الكائن من نوع ملف يختص بامكانية تصفحه بواسطة حلقة تكرار iterable، رأينا أعلاه كيف يمكننا قراءة ملف عبر حلقة تكرار. لكنه ايضا وسيط تكرار iterator لنفسه. هذا يعني أننا لانستطيع قراءته سوى مرة واحدة داخل حلقة تكرار. اذا اردنا قراته ثانية علينا غلقه واعادة فتحه من جديد. لاحظ:

كود :
with open("foo.txt", encoding='utf-8') as foo:
   print(foo.__iter__() is foo)      # True
   
lines1 = []
lines2 = []
with open("foo.txt", encoding='utf-8') as foo:
   for l1 in foo:
       lines1.append(l1.strip()) # تخزين في قائمة أولى
   for l2 in foo:
       lines2.append(l2.strip()) # تخزين في قائمة ثانية

print("lines1 =", lines1)
print("lines2 =", lines2)  # ليست النتيجة المنتظرة
يمكننا استخدام دوال وادوات قريبة من نظام التشغيل لمعالجة الملفات، مع التنبيه الى أنها طرق غير بيثونية. من بين ذلك:

## الدالة repr

كود :
with open("foo.txt", encoding='utf-8') as foo:
   for l1 in foo:
       print(l1)
       
with open("foo.txt", encoding='utf-8') as foo:
   for l1 in foo:
       print(repr(l1))
هذه الدالة ترد سلسلة نصية فيها ترميز المحارف غير المرئية.



## الدالة read

تقرأ أو تحاول أن تقرأ محتوى الملف بأكمله في شكل بايتات (محتوى منطقة التخزين buffer) لذلك لابد من الاحتياط ألا يكون الملف كبيرا جدا

كود :
with open("foo.txt", encoding='utf-8') as foo:
   full_contents = foo.read()
   print(full_contents)
نقرأ كمية محددة من البايتات (مفاجأة؟)

كود :
with open("foo.txt", encoding='utf-8') as foo:
   partial_contents = foo.read(2)
   print(partial_contents, type(partial_contents))
باستخدام الدالتين معا:

كود :
with open("foo.txt", encoding='utf-8') as foo:
   full_contents = repr(foo.read())
   print(full_contents)
## الدالة readline

كود :
with open("foo.txt", encoding='utf-8') as foo:
   line = foo.readline()
   while line :
       print(line, end='')
       line = foo.readline()
## فتح ملف لقراءته بصيغة ثنائية: 'rb' . لاحظ عدم استخدام الوسيط encoding

كود :
with open("foo.txt", 'rb') as foo:
   full_contents = foo.read()
   print(full_contents, type(full_contents))
للمقارنة (الترميز افتراضيا utf8)

كود :
with open("foo.txt", 'r') as foo:
   full_contents = foo.read()
   print(full_contents, type(full_contents))
هذا مثال آخر حيث نكتب في ملف جديد بترميز utf8 ثم نفتحه بصيغة ثنائية لنرى ترميز المحارف. اذا دققت الملاحظة ستكتشف أن ترميز الحروف العربية يستخدم بايتين اثنين



كود :
with open('strbytes', 'w', encoding='utf-8') as output:
   output.write("السلام عليكم")
   
with open('strbytes', 'rb') as rawinput:
   mybytes = rawinput.read()
   print(type(mybytes))
   for b in mybytes:
       print("{} → [{}]".format(repr(chr(b)), hex(b)))
حرف الالف وحده استخدم بايتين `[0xd8] و [0xa7]`

لاحظ أيضا أن طول سلسلتنا النصية يختلف بحسب عدد الحروف او عدد البايتات:

كود :
with open('strbytes', 'w', encoding='utf-8') as output:
   output.write("السلام عليكم")

with open('strbytes', encoding='utf-8') as textfile:
   print("Text mode, {} chars".format(len(textfile.read())))
with open('strbytes', 'rb') as binfile:
   print("Binary mode, {} bytes".format(len(binfile.read())))


## للمزيد من المعلومات يمكن كذلك مراجعة الروابط التالية:

https://docs.python.org/3/library/functions.html#open

https://docs.python.org/3/library/io.html#module-io
الرد


التنقل السريع :


مستخدمين يتصفحوا هذا الموضوع: 1 ضيف