كيفية قراءة الملفات بشكل صحيح في بايثون

هناك العديد من مبرمجي بايثون المبتدئين وحتى بعض المتقدمين يقومون بقراءة الملفات بالشكل التالي :


with open(“file.txt”) as f:
    contents = f.read()

وفي معظم الحالات فالكود مثل هذا سيعمل بشكل جيد ، فالتابع ()read سوف يقوم بقراءة كامل الملف في الذاكرة ويقوم بتخزينه في متغير contents .
وبالمقابل هناك التابع ()readlines يقوم بقراءة الملف كاملا في الذاكرة سطر بعد سطر في الوقت الواحد ويقوم بإضافة كل سطر في قائمة والكود التالي :

lines = f.readlines()

هو نفس الكود التالي :

lines = f.read().split(os.linesep)

بإستخدامنا ل os.linesep بدلا من “n\” سنكون متأكدين من أن الكود سيعمل على مختلف المنصات

ولكن ماذا يحدث عندما نريد قراءة ملف كبير والذي لا يتناسب مع الذاكرة ؟ مع بايثون إتضح لنا أنه يوجد بعض الطرق الجيدة و الجميلة 🙂 سواء كنا نريد قراءة الملف سطر سطر أو مرة واحدة .

أولا إليك هذه الطريقة الجملية والتي تسمح لنا بقراءة الملف سطر بسطر

with open("file.txt") as f:
    for line in f:
        process_line(line)

إذا كنت تتعامل مع الملفات النصية بشكل كبير فهذه أفضل طريقة لقراءة الملفات يمكن إستخدامها، وبينما نقرأ الملف قطعة قطعة فهذا يعني بطئ في العملية مقابل قراءة الملف كاملا وإلتهام الذاكرة ، إذن الأمر راجع إليك الأن يا صديقي 🙂

على كل حال هذه الطريقة تفترض أن ملفك يحتوي على فواصل الأسطر وقد لا يكون هذا هو حالك ، وإذا كنت تريد فعلا أن تتأكد من أن برنامجك يقرأ فقط عدد معين من الأحرف من خلال الملف ، يمكنك الإستفادة من حقيقة أن التابع ()read الخاص بالملفات يأخذ خيارات إختيارية ()read وعندما نقوم بإهمال الخيار n فالطريقة ستقرأ إلى غاية نهاية الملف ، وعندما يكون الخيار n حاضرا سوف يتم قراءة عدد معين من الحروف وهذا المثال يوضح العملية أكثر :

with open("file.txt") as f:
    while True:
        chunk = f.read(128)
        if chunk == "":
            break
        process_chunk(chunk)

في المثال السابق إعتمدنا على سلوك معين للتابع ()read حيث قام ب بإرجاع سلسلة فارغة عندما وصل إلى نهاية الملف ، فعند قراءة الملفات الغير معروفة الطول يقوم بقرائتها قطعة قطعة للخروج من الحلقة .

الكود السابق طويل نوعا ما ولكنه يقوم بواجبه ، ولكن هل توجد طريقة أخرى لكتابته ؟ أكيد يوجد !!! والكود التالي يقوم نفس الشيء :

with open("file.txt") as f:
    for chunk in iter(lambda: f.read(128), ""):
        process_chunk(chunk)

لتفهم هذا الكود جيدا عليك أن تفهم مالذي يجري عند تنفيذ وظيفة ()iter فهذه الأخيرة لديها مدخلة واحدة إلزامية والأخرى إختيارية وهي تتصرف بشكل مختلف إعتمادا على عدد المدخلات المقدمة ، ففي حالة وجود مدخل واحد فيجب أن يكون هذا المذخل كائن يدعم بروتوكول التكرار أي يجب تنفيذ تابع ()__iter__ أو بروتوكول التتابع أي يجب تنفيذ تابع ()__getitem__
وفي حالة وجود مدخلين فيجب على المدخل الأول أن يكون قابل للإستدعاء ويدعم التكرار iter(callable, sentinel)

وفي مايلي الكود السابق معدل بشكل طفيف للتعامل مع الملفات الثنائية :

with open("file.txt", "rb") as f:
    for chunk in iter(lambda: f.read(128), b""):
        process_chunk(chunk)

إلى هنا نكون قد إنتهينا وهذا لا يعني كل شيء ولكن نكتفي بهذه التقنيات الأساسية التي تمكن من قراءة الملفات والتي تحتاجها في تعاملك مع بايثون

أرجوا أن تقوم بدعمنا عبر نشرك والاعجاب بالموقع

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *

Post Navigation