مقالات مختارة

إعادة تسمية مئات الملفات دفعة واحدة باستخدام بايثون

إعادة تسمية مئات الملفات دفعة واحدة باستخدام بايثون وpathlib

يمكنك إعادة تسمية مئات الملفات دفعة واحدة باستخدام بايثون عبر pathlib، بتمرير حلقة على الملفات وبناء الاسم الجديد ثم تنفيذ Path.rename(). ويمكنك في نفس السكربت ترقيم الملفات تلقائيًا، إضافة Prefix أو Suffix، استبدال جزء من الاسم، أو استهداف امتداد محدد فقط.

سنبدأ بمعاينة Dry Run قبل لمس الملفات، ثم نضيف فحصًا يمنع استخدام اسم موجود مسبقًا.

قبل التنفيذ: استخدم نسخة تجريبية من المجلد واحتفظ بنسخة احتياطية. لا تشغّل سكربت إعادة تسمية جماعية على ملفات مهمة قبل أن تراجع الأسماء الجديدة.

النتيجة التي سنصل إليها

قبلبعد
photo_1.jpgproduct_001.jpg
photo_2.jpgproduct_002.jpg
photo_3.jpgproduct_003.jpg
شكل الملفات قبل وبعد إعادة التسمية الجماعية باستخدام بايثون

إعادة تسمية ملف واحد لفهم الفكرة

pathlib موجودة ضمن مكتبة بايثون القياسية ولا تحتاج إلى تثبيت.

from pathlib import Path

old_path = Path("photo_1.jpg")
new_path = Path("product_001.jpg")

old_path.rename(new_path)

هذا يغيّر اسم ملف واحد فقط. الفكرة نفسها ستتكرر لاحقًا داخل حلقة تمر على مئات الملفات.

مسار Windows الصحيح

إذا كان المجلد مثل C:\Users\Name\Pictures فاستخدم Raw String:

from pathlib import Path

folder = Path(
    r"C:\Users\Name\Pictures"
)

إعادة تسمية جميع الملفات مع ترقيم تلقائي

هذا المثال يوضح الترقيم والحفاظ على الامتداد، لكنه ينفذ التغيير فعليًا؛ استخدمه فقط على مجلد تجريبي:

from pathlib import Path

folder = Path("photos")

files = sorted(
    (
        file
        for file in folder.iterdir()
        if file.is_file()
    ),
    key=lambda file: file.name.lower()
)

for index, file in enumerate(files, start=1):
    new_name = (
        f"product_{index:03d}"
        f"{file.suffix}"
    )

    new_path = file.with_name(new_name)
    file.rename(new_path)

{index:03d} ينتج 001 و002 و003. واستخدام file.suffix يحافظ على امتداد الملف الأصلي.

استخدمنا sorted() لأن ترتيب iterdir() ليس ترتيبًا يجب الاعتماد عليه عند الترقيم.

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

إعادة تسمية ملفات JPG فقط مع Dry Run

from pathlib import Path

folder = Path("photos")

jpg_files = sorted(
    (
        file
        for file in folder.iterdir()
        if (
            file.is_file()
            and file.suffix.lower() == ".jpg"
        )
    ),
    key=lambda file: file.name.lower()
)

for index, file in enumerate(jpg_files, start=1):
    new_name = (
        f"product_{index:03d}"
        f"{file.suffix}"
    )

    print(
        f"{file.name} -> {new_name}"
    )

هنا لم نستخدم rename(). النتيجة مجرد معاينة للأسماء الجديدة. إذا رأيت:

  • photo_1.jpg -> product_001.jpg
  • photo_2.jpg -> product_002.jpg
  • photo_3.jpg -> product_003.jpg

فقد راجعت منطق التسمية قبل تغيير الملفات.

الفرق بين Dry Run وتنفيذ إعادة تسمية الملفات فعليًا في بايثون

إضافة Prefix إلى الاسم

new_name = (
    "invoice_"
    + file.name
)

print(new_name)

مثلًا 001.pdf تصبح invoice_001.pdf.

إضافة Suffix قبل الامتداد

new_name = (
    f"{file.stem}_final"
    f"{file.suffix}"
)

بهذا يصبح report.pdf هو report_final.pdf، بدل وضع النص بعد الامتداد.

استبدال جزء من الاسم

لتحويل old_report_01.xlsx إلى new_report_01.xlsx:

new_stem = file.stem.replace(
    "old_report",
    "new_report"
)

new_name = (
    new_stem
    + file.suffix
)

استخدام stem يجعل الاستبدال في اسم الملف دون العبث بالامتداد.

استبدال المسافات بشرطة سفلية

new_stem = (
    file.stem
    .strip()
    .replace(" ", "_")
)

new_name = (
    new_stem
    + file.suffix
)

مثلًا my photo 01.jpg تصبح my_photo_01.jpg.

منع تضارب أسماء الملفات

قبل التنفيذ افحص هل الاسم الجديد موجود بالفعل:

new_path = file.with_name(new_name)

if (
    new_path.exists()
    and new_path != file
):
    raise FileExistsError(
        f"Target exists: "
        f"{new_path.name}"
    )

file.rename(new_path)

هذا فحص محافظ يمنعك من متابعة العملية عندما يوجد ملف آخر بالاسم الجديد.

منع تضارب أسماء الملفات عند إعادة التسمية باستخدام بايثون

سكربت نهائي: معاينة أولًا ثم تنفيذ عند التأكد

السكربت التالي يجمع تحديد المجلد، اختيار الامتداد، ترتيب الملفات، الترقيم، الحفاظ على الامتداد، فحص تضارب الأسماء، ثم التنفيذ الاختياري.

from pathlib import Path


FOLDER = Path(
    r"C:\Users\Name\Pictures"
)

EXTENSION = ".jpg"
PREFIX = "product_"
APPLY_CHANGES = False


if not FOLDER.is_dir():
    raise FileNotFoundError(
        f"Folder not found: {FOLDER}"
    )


files = sorted(
    (
        file
        for file in FOLDER.iterdir()
        if (
            file.is_file()
            and file.suffix.lower()
            == EXTENSION.lower()
        )
    ),
    key=lambda file: file.name.lower()
)


planned = []

for index, file in enumerate(
    files,
    start=1
):
    new_name = (
        f"{PREFIX}{index:03d}"
        f"{file.suffix}"
    )

    new_path = file.with_name(new_name)

    planned.append(
        (file, new_path)
    )


for old_path, new_path in planned:
    if (
        new_path.exists()
        and new_path != old_path
    ):
        raise FileExistsError(
            f"Target already exists: "
            f"{new_path.name}"
        )


for old_path, new_path in planned:
    print(
        f"{old_path.name} "
        f"-> {new_path.name}"
    )


if APPLY_CHANGES:
    for old_path, new_path in planned:
        if old_path != new_path:
            old_path.rename(new_path)

    print("Rename completed.")

else:
    print(
        "Dry run only. "
        "No files were renamed."
    )

اترك APPLY_CHANGES = False في أول تشغيل. بعد مراجعة كل سطر من Old → New غيّرها إلى True ونفذ مرة أخرى.

ملاحظة عن ترتيب الأسماء

الترتيب السابق نصي. لذلك أسماء مثل photo_2.jpg وphoto_10.jpg قد لا تأتي بالترتيب العددي الذي يتوقعه الإنسان. إذا كان ترتيب الأرقام مهمًا، استخدم أسماء بأرقام ثابتة الطول مثل photo_002.jpg وphoto_010.jpg أو أضف Natural Sort مخصصة.

أخطاء شائعة

FileNotFoundError أو مسار خاطئ

تأكد أن FOLDER يشير إلى مجلد موجود. في Windows استخدم Raw String عند كتابة Backslashes يدويًا.

PermissionError

قد يكون الملف مفتوحًا في برنامج آخر أو لا تملك صلاحية تعديله. أغلق البرنامج وتحقق من الصلاحيات.

تشغيل السكربت على المجلد الخطأ

راجع قيمة FOLDER ونتيجة Dry Run قبل تغيير أي ملف.

الاسم الجديد موجود مسبقًا

افحص new_path.exists() وأوقف التنفيذ بدل المخاطرة بملف آخر.

إعادة تسمية السكربت نفسه

ضع السكربت خارج مجلد الملفات أو استهدف امتدادًا محددًا مثل JPG أو PDF.

تغيير الامتداد بالخطأ

استخدم stem لتعديل الاسم وsuffix للحفاظ على الامتداد.

روابط داخلية مفيدة من بايثون العرب

مصادر رسمية للتوسع

الخلاصة

إذا كان لديك عشرات أو مئات الملفات، استخدم pathlib لعرضها وبناء الأسماء الجديدة، وsorted() لتثبيت قاعدة الترتيب، وf"{index:03d}" للترقيم، وsuffix للحفاظ على الامتداد.

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

أفضل ممارسة: اجعل وضع المعاينة هو الوضع الافتراضي لأي سكربت يغيّر أسماء عدد كبير من الملفات.

أسئلة شائعة

كيف أعيد تسمية عدة ملفات باستخدام بايثون؟

اعرض الملفات داخل المجلد باستخدام Path.iterdir()، وابنِ الاسم الجديد داخل حلقة، ثم استخدم Path.rename() بعد معاينة النتيجة.

كيف أرقم الملفات تلقائيًا؟

استخدم enumerate() مع تنسيق مثل f"{index:03d}" للحصول على 001 و002 و003.

كيف أحافظ على امتداد الملفات؟

استخدم file.suffix عند بناء الاسم الجديد، وfile.stem للتعامل مع الاسم بدون الامتداد.

كيف أعيد تسمية ملفات JPG فقط؟

فلتر الملفات بشرط مثل file.suffix.lower() == ".jpg".

كيف أستبدل جزءًا من اسم الملف؟

استخدم file.stem.replace("old", "new") ثم أعد إضافة file.suffix.

كيف أتجنب الكتابة فوق ملف موجود؟

افحص new_path.exists() قبل rename()، وإذا كان الاسم موجودًا أوقف العملية أو اختر اسمًا آخر.

Admin
Admin
تعليقات