14-05-2018, 10:04 AM
# الملفات في بيثون
## تذكير
عند التعامل مع السلاسل النصية، من المهم معرفة ترميز المحارف المستخدم في السلسلة النصية سواء لقراءتها او لكتابتها. الترميز القياسي في بيثون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()
عبر الوسيط الثاني نحدد الغرض من فتح الملف: للكتابة فقط نستخدم '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) # طباعة النتيجة
كود :
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() # غلق الملف الثاني
## معالجة أخطاء الوصول الى الملفات عبر 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)
كود :
with open("foo.txt", encoding='utf-8') as foo:
line = foo.readline()
while line :
print(line, end='')
line = foo.readline()
كود :
with open("foo.txt", 'rb') as foo:
full_contents = foo.read()
print(full_contents, type(full_contents))
كود :
with open("foo.txt", 'r') as foo:
full_contents = foo.read()
print(full_contents, type(full_contents))
كود :
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)))
لاحظ أيضا أن طول سلسلتنا النصية يختلف بحسب عدد الحروف او عدد البايتات:
كود :
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