ملحق N — الملفات

وإليك تصنيف لعمليات مكتبة pathlib:

عمليات المسار

  • إنشاء وتعديل المسارات:
    • .joinpath: دمج مكونات مسار.
    • .parent: استخراج الدليل الأب.
    • .name: استخراج الاسم الأساسي للملف.
    • .stem: استخراج اسم الملف بدون الامتداد.
    • .suffix: استخراج امتداد الملف.
    • .with_name: إنشاء مسار جديد باسم مختلف.
    • .with_suffix: إنشاء مسار جديد بامتداد مختلف.
    • relative_to: إنشاء مسار نسبي.

عمليات على نظام الملفات

  • استعلام:
    • is_absolute: هل هو مطلق؟.
    • samefile: هل مساران يشيران إلى نفس الملف؟.
    • exists: هل هو مسار موجود؟.
    • is_file: هل هو مسار ملف؟.
    • is_dir: هل هو مسار دليل؟.
    • is_symlink: هل هو ارتباط رمزي؟.
    • stat: سرد إحصائيات نظام الملفات.
    • lstat: سرد إحصائيات نظام الملفات دون متابعة الارتباطات الرمزية.
  • عمليات تغيير:
    • open: فتح ملف للقراءة أو الكتابة أو الإضافة.
    • mkdir: إنشاء دليل.
    • rmdir: حذف دليل فارغ.
    • unlink: حذف ملف.
    • rename: تعديل اسم ملف.
    • replace: تعديل اسم ملف مع الكتابة فوقه إذا لزم الإجراء.
    • chmod: تغيير أذونات الملف.
    • lchmod: تغيير أذونات الملف دون متابعة الارتباطات الرمزية.
    • touch: تحديث الطابع الزمني للملف.

الارتباطات الرمزية والصلبة

  • symlink_to: إنشاء ارتباط رمزي.
  • hardlink_to: إنشاء ارتباط صلب.
  • readlink: قراءة الهدف من ارتباط رمزي.

الكر والبحث

  • iterdir: كر على قائمة الدليل.
  • glob: البحث عن الملفات المطابقة لنمط.
  • rglob: البحث بشكل متكرر عن الملفات المطابقة لنمط.
  • walk: التنقل بشكل متكرر في شجرة الأدلة.

النسخ والحذف والنقل (shutil)

المسار

المسار هو سلسلة تحدد موقع الملف في النظام. وهو على نوعين:

  1. مطلق (Absolute): يحدد المسار بشكل كامل بدءًا من الجذر.
  2. نسبي (Relative): يحدد المسار بالنسبة لموقع الملف الحالي.

وفواصل المسار شرطة مائلة:

  • / تميل للأمام (اليمين) في عُرف أنظمة ويندوز
  • \ تميل للخلف (اليسار) في عُرف أنظمة يونكس

والنقطة والنقطتان تدل على نسبية المسار:

  • . للدليل الحالي (هنا)
  • .. للدليل الأب (صعود)
Path Example
Absolute /home/adam/projects/xyz/scripts/analysis.py
Relative .
Relative ..
Relative ./a/b
Relative ../a/b
Relative a/b

يتم ترتيب الملفات شجريًّا.

ففي نظام ويندوز (Windows) تكون الشرطة خلفية (\):

C:\
└── Users
    └── Adam
        └── MyProject
            ├── data
            │   └── datafile.csv
            └── scripts
                └── analysis.py

فالحرف الأوَّل في الأعلى (C:) يمثِّل مكان جهاز التخزين. وإن رأيت D: أو E: فيعني أن الملفات تخزن في جهازين آخرين.

وقد تتساءل لماذا لم نبدأ بالحرف A: أو B:؟ وسبب ذلك تاريخي. وذلك أنَّهما كانا محجوزين للإشارة لجهاز تخزين عتيق يسمى القرص المرن (floppy disk)، ولم يعد يستعمل.

أما في أنظمة لينكس (Linux) وماك (MacOS) فإن الأصل يعبَّر عنه لا بحرف، وإنما بالمسار الجذر: / على النحو التالي:

/
└── home
    └── adam
        ├── projects
            └── myproject
                ├── data
                │   └── datafile.csv
                └── scripts
                    └── analysis.py

وتسمى الملفات المتضمنة لملفات أخرى: دليل (Directory). وهو الذي يعبَّر عنه فيما ترى في الواجهة الرسومية على شكل مجلَّد (Folder).

Folder Icon

Folder Icon

فإذًا الملفات على نوعين:

  1. ملف (File): وهو الذي يحوي بيانات نصية أو ثنائية. مثل:
    • datafile.csv ملف بيانات جدولية
    • analysis.py ملف برنامج بايثون
  2. دليل (Directory): وهو قائمة من الملفات والأدلة. مثل:
    • data دليل / مجلد البيانات
    • myproject دليل / مجلد المشروع

صيغة الملف (File Extension) تُعرَفُ بالحروف بعد آخر نقطة. مثل:

  • datafile.csv صيغة csv
  • analysis.py صيغة py

قراءة وكتابة الملفات

يتم فتح الملفات لغرض القراءة أو الكتابة بالإجراء open() هكذا:

f = open(file='salam.txt', mode='r')
content = f.read()
f.close()

print(content)
  • تم تحديد مسار الملف بالنسبة للملف الذي نحن فيه
  • تم تحديد وضع القراءة: mode='r' عند الفتح (open())
  • يتم قراءة المحتوى النصي للملف بالفعل: .read() المُسنَد إلى الملف file؛ ونعين قيمة ذلك في المتغير content
  • يتم إغلاق الملف حتى يستطيع برنامج آخر أن يفتحه؛ إذ لا يجيز نظام التشغيل أن يُفتح الملف في نفس الوقت من برنامجين مختلفين
  • تتم طباعة المحتوى الذي قُرئ

أما فتحُ الملف لغرض القراءة، فيتم بتحديد وضعية القراءة open(mode='w') على النحو التالي:

content = """Salam everyone,
I hope you are enjoying the course,

Thank you.
"""

f = open(file='salam.txt', mode='w')
f.write(content)
f.close()

print(content)

انظر مرجع قراءة وكتابة الملفات.

ولأن الفتح والإغلاق مقترنان في الموارد (Resources) المتنازع عليها (والذي يديرها نظام التشغيل)؛ فلا بد من الإغلاق بعد كل فتح. ووضع في اللغة مفهوم مدير السياق حيث يستعمل معها جملة with: فيكون ما بداخلها يعمل في سياق توفر المورِد، فإذا انتهت القطعة أغلِق المورِد تلقائيًّا. وبالمثال يتضح المقال:

contents = ''
with open(file='salam.txt', mode='r') as f:
    contents = f.read()
print(contents)

لاحظ أننا لم نحتج لفعل الإغلاق: f.close() بل يتم ذلك بعد آخر جملة مضمَّنة داخل نطاق with.

مكتبة المسار (pathlib)

from pathlib import Path

تعنى مكتبة المسار (pathlib) بجميع ما يخص المسار: إنشائه والبحث فيه والاستعلام عن مدلوله والسير فيه.

ملاحظة

يجدر بالذكر أن مكتبة pathlib جاءت متأخرة في إصدار Python 3.4 لمعالجة الملفات بأسلوب البرمجة الشيئية (OOP)، بينما تستعمل مكتبة os التي سبقتها لأغراض متعددة فيما يخص نظام التشغيل (os = Operating System) من ضمنها خُصِّصَت os.path للتتعامل مع نظام الملفات إلا أنها كُتِبَت بأسلوب إجرائي تأسيًّا بلغة سي (C)، فهي منخفضة المستوى (تتعامل مباشرة مع bytes و str) بالمقارنة بالبرمجة الشيئية الأعلى في التجريد؛ وهو ما نفضله. انظر مقارنة pathlib بوحدات os و os.path.

ويستعمل المسار Path مكان النص بعد إنشائه على النحو التالي:

p = Path('salam.txt')

contents = ''
with open(file=p, mode='r') as f:
    contents = f.read()
print(contents)

الدليل (Directory)

أحيانًا نريد التعامل مع مجلَّد يحوي مجموعة ملفات، بنقلها أو نسخها أو حذفها ونحو ذلك.

انظر قراءة الأدلة.

لعرض قائمة الدليل، نستعمل المكرر الناتج من فعل .iterdir() ونكرر عليه، وهو بدورِه يُنتج في كل كرةٍ مساراً (x). وهذا المسار يُمكن التحقق من أنه يشير إلى دليل أو لا (x.is_dir()) على النحو التالي:

p = Path('.')
dirs = [x for x in p.iterdir() if x.is_dir()]
dirs

جرب

هل تريد أن تعرف حجم دليل التنزيلات (Downloads) في جهازك؟. لديك الفعل stat() للحصول على بيانات عن الدليل، والتي من ضمنها الحجم (st_size) هكذا:

p = Path.home() / 'Downloads'
size = p.stat().st_size
print(size, 'bytes')

ثم هذا الإجراء لتحويل الوِحدة من البايت إلى الكيلو والميجا والقيقا:

def format_size(size):
    size_kb = size / 1024
    size_mb = size_kb / 1024
    size_gb = size_mb / 1024
    if size_gb > 0.1:
        return f'{size_gb:.2f} GB'
    elif size_mb > 0.1:
        return f'{size_mb:.2f} MB'
    return f'{size_kb:.2f} KB'

print(format_size(size))

البحث العام

يستعمل البحث العام (Globbing) لمطابقة عدة ملفات تحت مسار معيَّن بنمط معيَّن.

وهي لغة تنميط بسيطة جدًّا لا تقارن بتعقيد التعبيرات النمطية (Regular Expression) التي سبق ذكرها. وإليك تطبيقًا تفاعليًّا يجمع لك جميع مفاهيمها: globster.

مثلاً: نبحث في المسار path/to/my/pictures/ عن جميع الصور (ذات الصيغة .jpg) في كل ما يتفرع عن ذلك المسار وإن نزل:

total_size = 0
for p in Path('path/to/my/pictures/').glob('**/*.jpg'):
    total_size += p.stat().st_size

print('Total size:', total_size, 'bytes')
print('Total size:', format_size(total_size))

المشي على جميع ملفات الشجرة

نستعمل الفعل .walk() لطرق جميع فروع المسار:

p = Path('../../datasets/example_root/')
for dirpath, dirnames, filenames in p.walk(top_down=True):
    print(dirpath)
    for file in filenames:
        print(f'\t{file}')
        # print('\tFULL PATH:', Path(dirpath) / file)
../../datasets/example_root
    something.txt
../../datasets/example_root/a
    A_domestic_cat.jpg
    zzz.txt
    A_domestic_cat.jpgZone.Identifier
    a.txt
../../datasets/example_root/b
    DSC0532_(9120523417).jpg
    A_yellow_and_white_cat.jpg
    DSC0532_(9120523417).jpgZone.Identifier
    b.txt
    A_yellow_and_white_cat.jpgZone.Identifier
../../datasets/example_root/c
    c.txt
../../datasets/example_root/c/c_inner
    inner.txt

لاحظ أن .walk() يعطينا ثلاثة قيَم في كل كرة:

  • dirpath: المسار الحالي للدليل.
  • dirnames: قائمة بأسماء الأدلة التي يدل عليها.
  • filenames: قائمة بأسماء الملفات التي يدل عليها.

لإظهار كامل المسار؛ أزل علامة التعليق # من السطر الأخير لتنفيذه.

مصادر أخرى

  • إذا كنت تريد قراءة الملفات وكتابتها بشكل بسيط انظر: open().
  • وإذا كنت تريد التعامل مع الملفات المؤقتة فانظر: tempfile.
  • وكثير من عمليات التعامل مع الملفات والأدلة تجدها في: shutil.