وحدة pathlib في بايثون: ترويض نظام الملفات

تُسهّل وحدة pathlib في بايثون عملك مع مسارات الملفات والمجلدات. بدلًا من الاعتماد على معالجة المسارات التقليدية القائمة على السلاسل النصية، يمكنك استخدام كائن Path، الذي يوفر طريقة متعددة المنصات لقراءة الملفات وكتابتها ونقلها وحذفها.

تجمع pathlib أيضًا وظائف كانت منتشرة سابقًا في مكتبات أخرى مثل os وglob وshutil، مما يُسهّل عمليات الملفات. كما تتضمن أساليب مدمجة لقراءة وكتابة النصوص أو الملفات الثنائية، مما يضمن نهجًا سلسًا وفعّالًا في التعامل مع مهام الملفات.

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

مشكلة تمثيل المسارات كسلاسل

مع وحدة Pathlib في بايثون، يمكنك توفير بعض الوقت. ففئة Path المرنة تُمهد الطريق لدلالات بديهية. قبل أن تُلقي نظرة فاحصة على الفئة، خصص لحظة لترى كيف كان على مطوري بايثون التعامل مع المسارات قبل ظهور pathlib.

تقليديًا، كان بايثون يُمثِّل مسارات الملفات باستخدام سلاسل نصية عادية. ولكن، بما أن المسارات تتجاوز مجرد سلاسل نصية، فقد تم توزيع وظائف مهمة في جميع أنحاء المكتبة القياسية، بما في ذلك مكتبات مثل os وglob وshutil.

على سبيل المثال، تقوم كتلة التعليمات البرمجية التالية بنقل الملفات إلى مجلد فرعي:

import glob
import os
import shutil

for file_name in glob.glob("*.txt"):
    new_path = os.path.join("archive", file_name)
    shutil.move(file_name, new_path)

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

توفر وحدة pathlib في بايثون فئة Path تعمل بنفس الطريقة على أنظمة تشغيل مختلفة. بدلاً من استيراد وحدات نمطية مختلفة مثل glob وos وshutil، يمكنك تنفيذ نفس المهام باستخدام pathlib فقط:

from pathlib import Path

for file_path in Path.cwd().glob("*.txt"):
    new_path = Path("archive") / file_path.name
    file_path.replace(new_path)

كما في المثال الأول، يبحث هذا الكود عن جميع ملفات النصوص في المجلد الحالي وينقلها إلى مجلد فرعيarchive/. مع ذلك، باستخدام pathlib، يمكنك إنجاز هذه المهام باستخدام عدد أقل من عبارات الاستيراد وبنية لغوية أبسط، وهو ما ستتناوله بالتفصيل في الأقسام القادمة.

إنشاء مثيلات المسار باستخدام pathlib في بايثون

أحد دوافع pathlib هو تمثيل نظام الملفات بكائنات مخصصة بدلاً من السلاسل النصية. ومن المناسب تسمية التوثيق الرسمي لـ pathlib بـ pathlib – مسارات نظام الملفات الكائنية التوجه.

يتضح النهج الكائني التوجه بوضوح عند مقارنة بناء جملة pathlib بأسلوب os.path القديم. ويزداد وضوحًا عند ملاحظة أن جوهر pathlib هو فئة Path.

في الواقع، يتم استخدام Path بشكل متكرر لدرجة أنك عادةً ما تقوم باستيراده مباشرةً:

>>> from pathlib import Path
>>> Path
<class 'pathlib.Path'>

لأن عملك الرئيسي سيكون مع فئة Path من pathlib، فإن هذه الطريقة لاستيراد Path توفر عليك بعض ضغطات المفاتيح في الكود. بهذه الطريقة، يمكنك العمل مع Path مباشرةً، بدلاً من استيراد pathlib كوحدة والإشارة إلى pathlib.Path.

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

استخدام توابع المسار

بمجرد استيراد Path، يمكنك الاستفادة من التوابع الموجودة للحصول على دليل العمل الحالي أو دليل المستخدم الرئيسي.

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

بالإضافة إلى ذلك، من المفيد معرفة الدليل الرئيسي للمستخدم عند العمل مع الملفات. باستخدام الدليل الرئيسي كنقطة بداية، يمكنك تحديد مسارات تعمل على أجهزة مختلفة، بغض النظر عن أسماء المستخدمين.

للحصول على دليل العمل الحالي الخاص بك، يمكنك استخدام .cwd():

>>> from pathlib import Path
>>> Path.cwd()
WindowsPath('C:/Users/philipp/Desktop/pyarabic')

عند إنشاء pathlib.Path، ستحصل على كائن WindowsPath أو PosixPath. يعتمد نوع الكائن على نظام التشغيل الذي تستخدمه.

في نظام ويندوز، تُرجع الدالة .cwd() مسار WindowsPath. أما في لينكس وماك، فتُرجع مسار PosixPath. على الرغم من الاختلافات الجوهرية، تُوفر هذه الكائنات واجهات متطابقة للعمل معها.

بشكل عام، يُنصح باستخدام Path. باستخدامه، يمكنك إنشاء مسار فعلي للمنصة التي تستخدمها مع الحفاظ على استقلالية شيفرتك عن المنصة. تتيح لك المسارات الفعلية إجراء استدعاءات النظام على كائنات المسار، بينما تتيح لك المسارات النقية فقط التعامل مع المسارات دون الوصول إلى نظام التشغيل.

العمل مع مسارات مستقلة عن النظام الأساسي يعني أنه يمكنك كتابة نص برمجي على نظام ويندوز يستخدم Path.cwd()، وسيعمل بشكل صحيح عند تشغيل الملف على نظام ماك أو لينكس. وينطبق الأمر نفسه على .home():

>>> from pathlib import Path
>>> Path.home()
WindowsPath('C:/Users/philipp')

باستخدام Path.cwd() وPath.home()، يمكنك بسهولة الحصول على نقطة انطلاق لنصوص بايثون. في حال احتجت إلى كتابة المسارات أو الإشارة إلى بنية مجلد فرعي، يمكنك إنشاء Path باستخدام سلسلة نصية.

المرور في سلسلة

بدلاً من البدء في دليل المستخدم الرئيسي أو دليل العمل الحالي، يمكنك الإشارة إلى دليل أو ملف مباشرةً عن طريق تمرير تمثيله النصي إلى Path:

>>> from pathlib import Path
>>> Path(r"C:\Users\philipp\realpython\file.txt")
WindowsPath('C:/Users/philipp/Desktop/pyarabic/file.txt')

تُنشئ هذه العملية كائن Path. بدلًا من التعامل مع سلسلة نصية، يمكنك الآن استخدام المرونة التي توفرها مكتبة pathlib.

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

>>> r"C:\Users"
'C:\\Users'

السلسلة النصية التي يسبقها حرف r هي سلسلة نصية حرفية خام. في هذه السلسلة، تُمثل \ شرطة مائلة عكسية حرفية. في السلسلة النصية العادية، ستحتاج إلى استخدام شرطتين مائلتين عكسيتين (\\) للإشارة إلى أنك تريد استخدام الشرطة المائلة العكسية حرفيًا وليس كحرف إفلات.

ملاحظة: طريقة اصطلاحية للعمل مع موقع الوحدة الحالية حيث يستخدم المسار  __file__:

تحتوي السمة __file__ على مسار الملف الذي يستورده أو ينفّذه بايثون حاليًا. يمكنك تمرير __file__ إلى Path عند الحاجة إلى العمل مع مسار الوحدة نفسها. على سبيل المثال، قد ترغب في الحصول على الدليل الرئيسي باستخدام .parent.

ربما لاحظتَ بالفعل أنه على الرغم من إدخال المسارات في نظام ويندوز باستخدام الشرطة المائلة للخلف، فإن pathlib يمثلها باستخدام الشرطة المائلة للأمام (/) كفاصل للمسار. يُسمى هذا التمثيل بأسلوب POSIX.

POSIX هو اختصار لـ Portable Operating System Interface (واجهة نظام التشغيل المحمولة)، وهو معيار للحفاظ على التوافق بين أنظمة التشغيل. يغطي هذا المعيار أكثر بكثير من مجرد تمثيل المسار. يمكنك معرفة المزيد عنه في مواصفات المجموعة الأساسية المفتوحة، العدد 7.

مع ذلك، عندما تقوم بتحويل مسار إلى سلسلة، فسوف يستخدم النموذج الأصلي – على سبيل المثال، مع الخطوط المائلة العكسية على نظام التشغيل Windows:

>>> from pathlib import Path
>>> str(Path(r"C:\Users\gahjelle\realpython\file.txt"))
'C:\\Users\\gahjelle\\pyarabic\\file.txt'

بشكل عام، يُنصح بمحاولة استخدام كائنات Path قدر الإمكان في شفرتك البرمجية للاستفادة من مزاياها، ولكن قد يكون تحويلها إلى سلاسل نصية ضروريًا في بعض السياقات. لا تزال بعض المكتبات وواجهات برمجة التطبيقات تتوقع منك تمرير مسارات الملفات كسلاسل نصية، لذا قد تحتاج إلى تحويل كائن المسار إلى سلسلة نصية قبل تمريره إلى دوال معينة.

ربط المسارات

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

from pathlib import Path

for file_path in Path.cwd().glob("*.txt"):
    new_path = Path("archive") / file_path.name
    file_path.rename(new_path)

يمكن لمشغل الشرطة المائلة الأمامية ربط عدة مسارات أو مزيج من المسارات والسلاسل النصية، شريطة تضمين كائن Path واحد. يمكنك استخدام الشرطة المائلة الأمامية بغض النظر عن فاصل المسارات الفعلي في منصتك.

إذا كنت لا تحب تدوين الشرطة المائلة الخاصة، فيمكنك إجراء نفس العملية باستخدام التابع .joinpath():

>>> from pathlib import Path
>>> Path.home().joinpath("python", "scripts", "test.py")
PosixPath('/home/gahjelle/python/scripts/test.py')

هذا الترميز أقرب إلى os.path.join()، الذي ربما استخدمته سابقًا. قد يبدو مألوفًا أكثر من الشرطة المائلة للأمام إذا كنت معتادًا على المسارات ذات الشرطة المائلة للخلف.

بعد إنشاء مثيل ل Path، قد ترغب في تنفيذ إجراء ما عليه. على سبيل المثال، ربما ترغب في إجراء عمليات على ملف أو اختيار أجزاء منه. هذا ما ستفعله لاحقًا.

عمليات نظام الملفات باستخدام المسارات

يمكنك إجراء العديد من العمليات المفيدة على نظام الملفات لديك باستخدام pathlib. في هذا القسم، ستحصل على نظرة عامة شاملة على بعض العمليات الأكثر شيوعًا. ولكن قبل البدء بإجراء عمليات الملفات، ألقِ نظرة على أجزاء المسار أولًا.

اختيار مكونات المسار

يتكون مسار الملف أو المجلد من أجزاء مختلفة. عند استخدام pathlib، تتوفر هذه الأجزاء بسهولة كخصائص. من الأمثلة الأساسية:

  • .name: اسم الملف بدون أي دليل
  • .stem: اسم الملف بدون امتداد الملف
  • .suffix: امتداد الملف
  • .anchor: جزء المسار قبل المجلدات
  • .parent: الدليل الذي يحتوي على الملف، أو الدليل الرئيسي إذا كان المسار مجلدًا

هنا، يمكنك ملاحظة هذه الخصائص أثناء العمل:

>>> from pathlib import Path
>>> path = Path(r"C:\Users\gahjelle\pyarabic\test.md")
>>> path
WindowsPath('C:/Users/gahjelle/pyarabic/test.md')

>>> path.name
'test.md'

>>> path.stem
'test'

>>> path.suffix
'.md'

>>> path.anchor
'C:\\'

>>> path.parent
WindowsPath('C:/Users/gahjelle/pyarabic")

>>> path.parent.parent
WindowsPath('C:/Users/gahjelle')

لاحظ أن .parent يُرجع كائن مسار جديد، بينما تُرجع الخصائص الأخرى سلاسل نصية. هذا يعني، على سبيل المثال، أنه يمكنك ربط .parent في المثال الأخير، أو حتى دمجه مع عامل الشرطة المائلة لإنشاء مسارات جديدة تمامًا:

>>> path.parent.parent / f"new{path.suffix}"
PosixPath('/home/gahjelle/new.md')

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

لنفترض أنك تريد طباعة جميع عناصر قائمة التسوق التي دوّنتها في ملف Markdown. يبدو محتوى ملف shopping_list.md كما يلي:

<!-- shopping_list.md -->

# Shopping List

## Fruit

* Banana
* Apple
* Peach

## Candy

* Chocolate
* Nougat Bits

تقليديًا، كانت طريقة قراءة أو كتابة ملف في بايثون هي استخدام الدالة open() المدمجة. مع pathlib، يمكنك استخدام open() مباشرةً على كائنات Path.

لذا، قد تبدو المسودة الأولى من البرنامج النصي الخاص بك الذي يبحث عن جميع العناصر الموجودة في shopping_list.md ويطبعها على النحو التالي:

from pathlib import Path

path = Path.cwd() / "shopping_list.md"
with path.open(mode="r", encoding="utf-8") as md_file:
    content = md_file.read()
    groceries = [line for line in content.splitlines() if line.startswith("*")]
print("\n".join(groceries))

في الواقع، تستدعي دالة Path.open() دالة open() المُدمجة. لذلك، يمكنك استخدام معلمات مثل الوضع والترميز مع Path.open().

بالإضافة إلى ذلك، يوفر pathlib بعض التوابه المريحة لقراءة الملفات وكتابتها:

  • .read_text() يفتح المسار في وضع النص ويعيد المحتويات كسلسلة نصية.
  • .read_bytes() يفتح المسار في الوضع الثنائي ويعيد المحتويات كسلسلة بايتية.
  • .write_text() يفتح المسار ويكتب بيانات سلسلة نصية إليه.
  • .write_bytes() يفتح المسار في الوضع الثنائي ويكتب البيانات إليه.

كلٌّ من هذه التوابع تتولى فتح الملف وإغلاقه. لذلك، يمكنك تحديث read_shopping_list.py باستخدام .read_text():

from pathlib import Path

path = Path.cwd() / "shopping_list.md"
content = path.read_text(encoding="utf-8")
groceries = [line for line in content.splitlines() if line.startswith("*")]
print("\n".join(groceries))

يمكنك أيضًا تحديد المسارات مباشرةً كأسماء ملفات، وفي هذه الحالة تُفسَّر بالنسبة إلى دليل العمل الحالي. لذا، يمكنك تلخيص المثال أعلاه بشكل أكبر:

from pathlib import Path

content = Path("shopping_list.md").read_text(encoding="utf-8")
groceries = [line for line in content.splitlines() if line.startswith("*")]
print("\n".join(groceries))

إذا كنت تريد إنشاء قائمة تسوق عادية تحتوي فقط على البقالة، فيمكنك استخدام .write_text() بطريقة مماثلة:

from pathlib import Path

content = Path("shopping_list.md").read_text(encoding="utf-8")
groceries = [line for line in content.splitlines() if line.startswith("*")]

Path("plain_list.md").write_text("\n".join(groceries), encoding="utf-8")

عند استخدام .write_text()، يُلغي بايثون أي ملفات موجودة على نفس المسار دون إشعارك. هذا يعني أنه يمكنك محو كل جهدك بضغطة زر واحدة! كما هو الحال دائمًا، عند كتابة ملفات باستخدام بايثون، يجب أن تكون حذرًا بشأن ما يفعله الكود. وينطبق الأمر نفسه عند إعادة تسمية الملفات.

إعادة تسمية الملفات

عند إعادة تسمية الملفات، يمكنك استخدام الدوال .with_stem() أو .with_suffix() أو .with_name(). تُرجع هذه الدوال المسار الأصلي، مع استبدال اسم الملف أو امتداده أو كليهما.

إذا كنت تريد تغيير امتداد الملف، فيمكنك استخدام .with_suffix() مع .replace():

>>> from pathlib import Path
>>> txt_path = Path("/home/gahjelle/pyarabic/hello.txt")
>>> txt_path
PosixPath("/home/gahjelle/pyarabic/hello.txt")

>>> md_path = txt_path.with_suffix(".md")
PosixPath('/home/gahjelle/pyarabic/hello.md')

>>> txt_path.replace(md_path)

باستخدام .with_suffix()، يتم إرجاع مسار جديد. لإعادة تسمية الملف، استخدم .replace(). هذا ينقل مسار txt_path إلى md_path ويعيد تسميته عند الحفظ.

إذا كنت تريد تغيير اسم الملف بالكامل، بما في ذلك الامتداد، فيمكنك استخدام .with_name():

>>> from pathlib import Path
>>> txt_path = Path("/home/gahjelle/pyarabic/hello.txt")
>>> txt_path
PosixPath("/home/gahjelle/pyarabic/hello.txt")

>>> md_path = txt_path.with_name("goodbye.md")
PosixPath('/home/gahjelle/pyarabic/goodbye.md')

>>> txt_path.replace(md_path)

يقوم الكود أعلاه بإعادة تسمية hello.txt إلى goodbye.md.

إذا كنت ترغب في إعادة تسمية اسم الملف فقط، مع الاحتفاظ باللاحقة كما هي، فيمكنك استخدام .with_stem(). ستستكشف هذه الطريقة في القسم التالي.

نسخ الملفات

من المثير للدهشة أن Path لا يحتوي على طريقة لنسخ الملفات. ولكن بفضل المعرفة التي اكتسبتها حتى الآن حول pathlib، يمكنك إنشاء الوظيفة نفسها ببضعة أسطر من التعليمات البرمجية:

>>> from pathlib import Path
>>> source = Path("shopping_list.md")
>>> destination = source.with_stem("shopping_list_02")
>>> destination.write_bytes(source.read_bytes())

أنت تستخدم دالة .with_stem() لإنشاء اسم الملف الجديد دون تغيير الامتداد. تتم عملية النسخ الفعلية في السطر المُظلل، حيث تستخدم دالة .read_bytes() لقراءة محتوى المصدر، ثم كتابة هذا المحتوى إلى الوجهة باستخدام دالة .write_bytes().

مع أن استخدام pathlib لكل ما يتعلق بالمسارات أمرٌ مُغري، يُمكنك أيضًا استخدام shutil لنسخ الملفات. إنه بديل رائع يُجيد التعامل مع كائنات Path.

نقل وحذف الملفات

من خلال pathlib، يمكنك أيضًا الوصول إلى العمليات الأساسية على مستوى نظام الملفات، مثل نقل الملفات وتحديثها وحتى حذفها. في أغلب الأحيان، لا تُصدر هذه الطرق تحذيرًا أو تنتظر تأكيدًا قبل حذف المعلومات أو الملفات. لذا، توخَّ الحذر عند استخدامها.

لنقل ملف، يمكنك استخدام دالة .replace(). لاحظ أنه إذا كانت الوجهة موجودة بالفعل، فستستبدلها دالة .replace(). لتجنب احتمالية استبدال مسار الوجهة، يمكنك التحقق من وجود الوجهة قبل الاستبدال:

from pathlib import Path

source = Path("hello.py")
destination = Path("goodbye.py")

if not destination.exists():
    source.replace(destination)

مع ذلك، هذا يترك المجال مفتوحًا لاحتمالية حدوث حالة تعارض. قد تُضيف عملية أخرى ملفًا في مسار الوجهة بين تنفيذ عبارة if ودالة .replace(). إذا كان هذا مُقلقًا، فالطريقة الأكثر أمانًا هي فتح مسار الوجهة للإنشاء الحصري، ثم نسخ بيانات المصدر صراحةً وحذف ملف المصدر بعد ذلك:

from pathlib import Path

source = Path("hello.py")
destination = Path("goodbye.py")

try:
    with destination.open(mode="xb") as file:
        file.write(source.read_bytes())
except FileExistsError:
    print(f"File {destination} exists already.")
else:
    source.unlink()

إذا كانت الوجهة موجودة بالفعل، فسيلتقط الكود أعلاه خطأ FileExistsError ويطبع تحذيرًا. لإجراء نقل، يجب حذف المصدر باستخدام .unlink() بعد انتهاء النسخ. يضمن استخدام else عدم حذف ملف المصدر في حال فشل النسخ.

إنشاء ملفات فارغة

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

>>> from pathlib import Path
>>> filename = Path("hello.txt")
>>> filename.exists()
False

>>> filename.touch()
>>> filename.exists()
True

>>> filename.touch()

في المثال أعلاه، يمكنك إنشاء كائن Path وإنشاء الملف باستخدام دالة .touch(). تستخدم دالة .exists() للتحقق من عدم وجود الملف سابقًا، ثم للتحقق من نجاح إنشائه. عند استخدام دالة .touch() مرة أخرى، يتم تحديث وقت تعديل الملف.

إذا كنت لا تريد تعديل الملفات عن طريق الخطأ، فيمكنك استخدام معلمة exist_ok وتعيينها إلى False:

>>> filename.touch(exist_ok=False)
Traceback (most recent call last):
  ...
FileExistsError: [Errno 17] File exists: 'hello.txt'

عند استخدام دالة .touch() على مسار ملف غير موجود، يُنشأ ملف بدون أي محتوى. إنشاء ملف فارغ باستخدام دالة ()Path.touch مفيد عندما ترغب في حفظ اسم ملف لاستخدامه لاحقًا، ولكن ليس لديك أي محتوى للكتابة إليه بعد. على سبيل المثال، قد ترغب في إنشاء ملف فارغ لضمان توفر اسم ملف معين، حتى لو لم يكن لديك محتوى للكتابة إليه حاليًا.

أمثلة على pathlib

في هذا القسم، ستشاهد بعض الأمثلة حول كيفية استخدام pathlib للتعامل مع التحديات اليومية التي تواجهها كمطور بايثون. يمكنك استخدام هذه الأمثلة كنقطة انطلاق لشفرتك البرمجية الخاصة أو حفظها كمقتطفات برمجية للرجوع إليها لاحقًا.

عد ملفات

هناك عدة طرق مختلفة للحصول على قائمة بجميع الملفات في مجلد باستخدام بايثون. باستخدام pathlib، يمكنك بسهولة استخدام دالة .iterdir()، التي تُكرر جميع الملفات في المجلد المحدد. في المثال التالي، يمكنك دمج دالة .iterdir() مع فئة collections.Counter لحساب عدد الملفات من كل نوع في المجلد الحالي:

>>> from pathlib import Path
>>> from collections import Counter
>>> Counter(path.suffix for path in Path.cwd().iterdir())
Counter({'.md': 2, '.txt': 4, '.pdf': 2, '.py': 1})

يمكنك إنشاء قوائم ملفات أكثر مرونة باستخدام الدوال .glob() و.rglob(). على سبيل المثال، تُرجع الدالة Path.cwd().glob(“*.txt”) جميع الملفات التي تحتوي على لاحقة .txt في المجلد الحالي. في المثال التالي، تُحسب امتدادات الملفات التي تبدأ بـ p فقط:

>>> Counter(path.suffix for path in Path.cwd().glob("*.p*"))
Counter({'.pdf': 2, '.py': 1})

إذا كنت ترغب في البحث بشكل متكرر عن جميع الملفات في كلٍّ من الدليل ومجلداته الفرعية، فيمكنك استخدام .rglob(). تُتيح هذه الطريقة أيضًا طريقةً رائعةً لعرض شجرة الدليل، وهو المثال التالي.

العثور على الملف الذي تم تعديله مؤخرًا

تُعد دوال .iterdir() و.glob() و.rglob() مثاليةً لتعبيرات المولدات وفهم القوائم. للعثور على أحدث ملف مُعدّل في دليل، يمكنك استخدام دالة .stat() للحصول على معلومات حول الملفات الأساسية. على سبيل المثال، تُعطي دالة .stat().st_mtime وقت آخر تعديل للملف:

>>> from pathlib import Path
>>> from datetime import datetime
>>> directory = Path.cwd()
>>> time, file_path = max((f.stat().st_mtime, f) for f in directory.iterdir())
>>> print(datetime.fromtimestamp(time), file_path)
2023-03-28 19:23:56.977817 /home/gahjelle/pyarabic/test001.txt

يمثل الطابع الزمني المُرجع من خاصية مثل .stat().st_mtime الثواني منذ 1 يناير 1970، والمعروفة أيضًا باسم الحقبة الزمنية. إذا كنت تفضل تنسيقًا مختلفًا، فيمكنك استخدام time.localtime أو time.ctime لتحويل الطابع الزمني إلى صيغة أكثر قابلية للاستخدام.

إنشاء اسم ملف فريد

في المثال الأخير، ستنشئ اسم ملف مرقمًا فريدًا بناءً على سلسلة نصية نموذجية. قد يكون هذا مفيدًا عندما لا ترغب في استبدال ملف موجود إذا كان موجودًا بالفعل:

def unique_path(directory, name_pattern):
    counter = 0
    while True:
        counter += 1
        path = directory / name_pattern.format(counter)
        if not path.exists():
            return path

في دالة ()unique_path، تُحدد نمطًا لاسم الملف، مع مساحة للعداد. ثم تتحقق من وجود مسار الملف الناتج عن ربط الدليل واسم الملف، بما في ذلك قيمة العداد. إذا كان موجودًا بالفعل، فزد قيمة العداد وحاول مرة أخرى.

الآن يمكنك استخدام البرنامج النصي أعلاه للحصول على أسماء ملفات فريدة:

>>> from pathlib import Path
>>> from unique_path import unique_path
>>> template = "test{:03d}.txt"
>>> unique_path(Path.cwd(), template)
PosixPath("/home/gahjelle/pyarabic/test003.txt")

إذا كان الدليل يحتوي بالفعل على الملفات test001.txt وtest002.txt، فإن الكود أعلاه سوف يعين المسار إلى test003.txt.

توفر وحدة pathlib في بايثون طريقةً حديثةً ومتوافقةً مع بايثون للتعامل مع مسارات الملفات، مما يجعل الكود أسهل قراءةً وصيانةً. باستخدام pathlib، يمكنك تمثيل مسارات الملفات بكائنات Path مخصصة بدلاً من السلاسل النصية العادية.

تُسهّل وحدة pathlib التعامل مع مسارات الملفات بتوفير أساليب وخصائص مفيدة. يُخفي كائن Path خصائص الأنظمة المختلفة، مما يجعل شيفرتك أكثر اتساقًا عبر أنظمة التشغيل.


اكتشاف المزيد من بايثون العربي

اشترك للحصول على أحدث التدوينات المرسلة إلى بريدك الإلكتروني.

اترك تعليقاً

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

Scroll to Top

اكتشاف المزيد من بايثون العربي

اشترك الآن للاستمرار في القراءة والحصول على حق الوصول إلى الأرشيف الكامل.

Continue reading