برنامج بلغة بايثون لتنظيم الملفات.
كيف تُبرمج سكريبت بايثون يقوم بتنظيم ملفات مُجلد ما بدلا عنك؟.
المقدمة:
لربما لديك مجلد تضع به كل أنواع الملفات من فيديوهات و صور إلى ملفات مضغوطة و غيرها، و كل مرة تخبر نفسك أنك ستقوم بتنظيمه لكن لما ترى تلك الفوضى تتهرب و تُبقيه على ذاك الحال، حسنا أتفق معك في هذا خاصة و لو كان مجلدك به أكثر من 50 ملف، ستتعب فقط بمجرد التفكير في أنك ستُضطر للقيام بالكثير من البحث و النسخ و اللصق.
في هذا المقال:
لحل هذه المشكلة، سنقوم بكتابة برنامج بايثون يقوم بهذا العمل المٌمل بدلا عنا و كل ما يحتاجه هذا البرنامج منك هو مسار المُجلد المُراد تنظيمه، كما أنه بانتهائك من قراءة ( وتطبيق ) هذا المقال ستأخذ نظرة لا بأس بها عن كيفية التعامل مع الملفات عن طريق بايثون.
بيان نِطاق المشروع:
البرنامج سيقوم بتنظيم ملفات مجلد معين، و تصنيفها حسب 6 تصنيفات ( Documents, Compressed, Videos, Programs, Music, Images ) البرنامج سيقوم بالتالي:
-
تحديد التصنيفات.
-
الحصول على مسار المجلد المراد تنظيمه إما عن طريق وسائط سطر الأوامر، أو من الحافِظة.
-
التحقق من أن مسار المجلد صحيح.
-
التحقق إذا كان هناك مجلدات للتصنيفات المحددة، إذا لم يكن كذلك البرنامج سيقوم بإنشاء مجلدات للتصنيفات.
-
الحصول على قائمة بها جميع الملفات الموجودة بالملف.
-
المرور على جميع الملفات و نقل كل ملف حسب إمتداده إلى التصنيف الذي ينتمي له.
كتابة البرنامج:
قبل أن نبدأ بكتابة الكود البرمجي، سأخبرك أن هذا المقال ليس موجه لتعلم أساسيات بايثون، لذلك ينبغي أن تكون على معرفة ( و لو بسيطة ) بأساسيات اللغة من حلقات و جمل شرطية و غيرها.
سنحتاج كذلك لوحدة - pyperclip - هذا الأخير سيساعدنا في التعامل مع الحافظة - clipboard - ( كل شيء تقوم بنسخه - Copy - يُخزن في ما يُسمى بالحافظة )، لتثبيت هذه الوحدة أدخل السطر التالي في الطرفية أو cmd ( حسب نظام التشغيل الذي تستعمله ):
و الآن لنبدأ على بركة الله.
الخطوة الأولى:
إفتح مُحرر الأكواد الخاص بك، و أنشئ ملف بايثون جديد و سمه كيف تشاء، أنا سميته files_manager.py، و اكتب فيه ما يلي:
# files_manager.py - Orgnize files of the given folder.
import sys, os, shutil, pyperclip
سنحتاج إلى 4 وحدات - Modules - و هي:
-
وحدة sys: للتعامل مع وسائط سطر الأوامر - command line arguments -.
-
وحدة os: للتعامل مع المسارات - paths -.
-
وحدة shutil: للتعامل مع الملفات ( نقل الملفات ).
-
وحدة pyperclip: للتعامل مع الحافظة - clipboard -
الخطوة الثانية:
لتحديد التصنيفات سننشئ قائمة من نوع tuple - قائمة ثابتة الحجم - و نضع بها التصنفيات التي نرغب بها:
# مجلدات التصنيفات.
CLASSES = ('Documents', 'Compressed', 'Programs', 'Videos', 'Music','Images')
DOCUMENTS, COMPRESSED, PROGRAMS, VIDEOS, MUSIC, IMAGES = CLASSES
في السطر الثاني نقوم بإنشاء متغيرات ستُسهِّل علينا عملية نقل الملفات حسب التصنيفات، و نُعرِّف كل متغير بقيمة من قائمة التصنيفات حسب الترتيب، اي كما لو أننا نقوم بالأمر التالي لكن بكتابة أقل:
# هذا الكود يقوم بنفس الأمر السابق.
CLASSES = ('Documents', 'Compressed', 'Programs', 'Videos', 'Music','Images')
DOCUMENTS = CLASSES[0]
COMPRESSED = CLASSES[1]
PROGRAMS = CLASSES[2]
VIDEOS = CLASSES[3]
MUSIC = CLASSES[4]
IMAGES = CLASSES[5]
الخطوة الثالثة:
الآن يلزمنا الحصول على مسار المجلد المُراد تنظيمه، و يوجد طريقتين:
إما عن طريق وسائط سطر الأوامر، و ما أقصده بهذا هو لما تريد مثلا تشغيل هذا البرنامج الحالي ستقوم بتشغيله من المحرر الخاص بك أو عن طريق سطر الأوامر هكذا:
في مكان some_arguments سيكون مسار المُجلد:
أو عن طريق الذهاب للمجلد و نسخ مساره و ترك البرنامج يتكفل بالمسار المنسوخ باستخدام وحدة pyperclip.
للتكفل بكلا من الطريقتين أضف الأسطر الآتية للسكريبت:
# الحصول على مسار المُجلد.
if len(sys.argv) > 1:
folder_path = sys.argv[1]
else:
folder_path = pyperclip.paste()
folder_path = os.path.abspath(folder_path)
في الوحدة sys يوجد متغير argv إختصار لـ' Arguments Vector ' و هي قائمة بها وسائط سطر الأوامر، لذلك نرى إن كان حجم القائمة أكبر من 1 فهذا يعني أنه تم تمرير مسار المجلد ضمن الوسائط عند تشغيل البرنامج و للتوضيح أكثر المُتغير argv سيحمل أحد القيمتين التاليتين:
- في حال تمرير مسار المجلد عند تشغيل البرنامج:
# قيمة المتغير
# argv
# إذا مررنا وسائط سطر الأوامر للبرنامج.
['files_manager.py', 'D:\MyFolder']
كما ترى العنصر الأول هو إسم البرنامج، و العنصر الثاني هو مسار المُجلد، و لهذا نقوم بتعريف متغير ( folder_path ) و نُعطيه قيمة العنصر الثاني حتى نحتفظ بالمسار.
- في حال لم يتم تمرير مسار المجلد ضمن الوسائط :
# قيمة المتغير
# argv
# إذا لمم نمرر وسائط سطر الأوامر للبرنامج.
['files_manager.py']
في هذه الحالة حجم القائمة ليس أكبر من 1 ما يعني أننا شَغَّلنا البرنامج بدون وسائط الأوامر، و لهذا نفترض أننا قُمنا بنسخ مسار المجلد فنستعين بالوحدة pyperclip و نستدعي الدالة ()past التي تُلصق ما هو مُخزن في الحافظة للمتغير ( folder_path )، فمثلا لو قمت بنسخ المسار التالي D:\MyFolder الدالة ()past ستُلصق هذه القيمة في المتغير ( folder_path ) و بالتالي قيمة هذا الأخير ستكون:
# قيمة المتغير
# folder_path
# إذا نسخت المسار
# D:\MyFolder
'D:\MyFolder'
في السطر الأخير نقوم بجعل المسار، مسارا كاملا - Absolute Path - و لفهم هذه النقطة يلزم أن تعرف أنه في المسارات يوجد نوعان:
- المسارات الكاملة - Absolute Path - ( أو المُطلقة ) مثل: D:\MyFolder أو C:\User\Shaheen تُعرف بهذا الإسم لأنها تُعطي مسارا كاملا لمكان وجود الملف أو المجلد.
- المسارات النسبية - Relative Paths - و هذه تعتمد على رمزين هما . و .. الأول معناه ' المُجلد الحالي ' و الثاني معناه ' المجلد الأب ' فمثلا يمكننا تشغيل البرنامج الخاص بنا و إعطائه مسارا من هذا الشكل:
المسار MyFolder\. يعني ' ضمن المجلد الحالي يوجد مجلد بإسم MyFolder ' كما يمكن تقديم مسار من هذا الشكل:
المسار MyFolder\.. يعني ' ضمن المجلد الأب للمجلد الحالي يوجد مجلد بإسم MyFolder '.
و لهذا نستعمل دالة ()abspath للتحويل من المسارات النسبية إلى المسارات الكاملة، و ذلك لأن المسارات النسبية قد يكون فيها نسبة أخطاء أكبر.
الخطوة الرابعة:
قبل البدأ في العمل مع الملفات ينبغي التحقق من أن المسار المُقدم مسار صحيح و ليس به أخطاء، لذلك أضف ما يلي:
# Check folder path validity.
if not os.path.exists(folder_path):
print('Invalid folder path.')
sys.exit(1)
نستعمل الدالة ()exists التي تتأكد من صِحة المسار و تُرجع إما True أو False لذلك إن لم يكن المسار صحيحا نطبع جملة ' .Invalid folder path '، و نُلغي تشغيل البرنامج بالدالة ()exit و نمرر لها الرقم 1 ( يمكن إستدعاء الدالة دون تمرير شيء لكن تمرير رقم ( عدا الـ0 ) يعني أنه حدث خطأ أثناء تشغيل البرنامج ).
الخطوة الخامسة:
في هذه الخطوة سنتحقق من وجود مُجلد لكل من التصنيفات التي حددناها سابقا، إن لم يكن هناك مجلد لتصنيف ما سنقوم بإنشائه:
# التحقق من توفر مجلد لكل من التصنيفات الحالية.
for c in CLASSES:
class_folder = os.path.join(folder_path, c)
if os.path.exists(class_folder):
print(c + ' Folder found.')
else:
print('Making directory for %s' % c)
os.mkdir(class_folder)
نمُر على عناصر قائمة التصنيفات، و نُنشئ متغير بإسم class_folder الذي سيحمل مسار مجلد التصنيف فمثلا من أجل تصنيف Documents قيمة المتغير ستكون:
# قيمة المتغير
# class_folder
# في حالة ما إذا كان التصنيف الحالي هو
# Documents.
'D:\MyFolder\Documents'
قد تتساءل لماذا نستعمل الدالة ()join ولا نقوم بالأمر هكذا:
class_folder = folder_path + '\\' + c
هذا السطر سيُنتج نفس المسار السابق من أجل تصنيف Documents، لكن هذا صحيح فقط من أجل نظام Windows ماذا عن مستخدمي أنظمة GNU/Linux؟ في توزيعات لينكس مسار الملفات يستخدم الرمز ' / ' بدلا من الرمز ' \ ' و هذا ما سيؤدي بحدوث خطأ في برنامجنا بالنسبة لأنظمة GNU/Linux، و لهذا نستعين بالدالة ()join التي ستتكفل بالرمز المُستخدم في المسارات.
ملاحظة: كما تعلم الرمز ' \ ' في بايثون يُعتبر رمز هروب ( escape charachter ) حيث يستخدم لطباعة ( أو إضافتها لمتغير نصي ) بعض الرموز، مثلا لو أردت طباعة الرمز ' إما أن تضعه بين " هكذا
" ' "
أو تستخدم رمز الهروب ( لن يتم طباعة رمز الهروب ):
'\''
غير هذا، سحصل خطأ في برنامجك، و لذلك الرمز ' \ ' لديه خاصية معينة في البايثون، و لتحديد أنك تريد الرمز نفسه و ليس رمز الهروب يجب أن تضيف رمز هروب قبله ( حتى تحدد أنك تريد طباعة الرمز نفسه و ليس خاصية الهروب ):
'\\'
الخطوة السادسة:
و الآن نحتاج لقائمة بها جميع الملفات الموجودة بالمجلد، حتى يمكننا نقلها حسب إمتدادها ( نوعها ):
# قائمة بها جميع الملفات الموجودة بالمجلد.
files = os.listdir(folder_path)
نمرر مسار المجلد للدالة ()listdir و هذه الأخيرة ستُرجع قائمة بها أسماء كل الملفات الموجودة في المجلد.
الخطوة السابعة و الأخيرة:
ما علينا الآن سوى المرور على كل الملفات و تحديد نوع كل ملف، و نقل الملف حسب نوعه إلى التصنيف الذي ينتمي له:
# المرور على كل الملفات و نقل كل ملف إلى التصنيف الذي ينتمي له.
for file in files:
file_path = os.path.join(folder_path, file)
if os.path.isdir(file_path):
continue
if file.endswith('.pdf') or file.endswith('.txt') or file.endswith('.odt') or file.endswith('.docx'):
print('Moving %s to %s...' % (file, DOCUMENTS))
#shutil.move(file_path, os.path.join(folder_path, DOCUMENTS))
elif file.endswith('.zip') or file.endswith('.rar') or file.endswith('.tar'):
print('Moving %s to %s...' % (file, COMPRESSED))
#shutil.move(file_path, os.path.join(folder_path, COMPRESSED))
elif file.endswith('.deb') or file.endswith('.rpm') or file.endswith('.exe') or file.endswith('.AppImage'):
print('Moving %s to %s...' % (file, PROGRAMS))
#shutil.move(file_path, os.path.join(folder_path, PROGRAMS))
elif file.endswith('.mp4') or file.endswith('.mkv'):
print('Moving %s to %s...' % (file, VIDEOS))
#shutil.move(file_path, os.path.join(folder_path, VIDEOS))
elif file.endswith('.mp3'):
print('Moving %s to %s...' % (file, MUSIC))
#shutil.move(file_path, os.path.join(folder_path, MUSIC))
elif file.endswith('.png') or file.endswith('.jpg') or file.endswith('.jpeg') or file.endswith('.svg'):
print('Moving %s to %s...' % (file, IMAGES))
#shutil.move(file_path, os.path.join(folder_path, IMAGES))
print('Done!')
جزء كبير أليس كذلك؟ لكن ما يقوم به أمر بسيط جدا، في السطر الأول ( بعد الحلقة ) نقوم بتحديد مسار الملف باستخدام الدالة ()join ثم بعدها نتحقق إذا ما كان هذا الملف مجلد، إذا كان كذلك نتجاوز ما تبقى من الكود و نمُر للملف التالي.
إذا لم يكن كذلك نتحقق من إمتداد الملف الحالي ( الإمتدادات هي التي تحدد نوع الملف ملا الملفات النصية تنهتي بها إمتداد txt. ) و للتحقق من الإمتداد نستعين بالدالة ()endswith التي نمرر لها الإمتداد و ستحقق ما إذا كان الملف ينتهي بهذا الإمتداد أو لا.
إذا كان الملف به ينتهي بالإمتداد الذي حددناه نطبع الجملة ' ...Moving %s to %s ' حيث s% الأول سيحمل الإسم الملف و الثاني إسم التصنيف الذي سيُنقل له الملف، كما يمكن أن ترى أنني علقت السطر الذي به ()shutil.move هذا السطر هو من يقوم بعملية نقل الملفات، و قم بتعليقه حتى نُشَّغل البرنامج على الأقل مرة واحدة و نتأكد من أنه يعمل بشكل جيد دون أخطاء، عن طريق رؤية ما يتم طباعته لنا في سطر الأوامر بعدها يمكننا إعادة السطر للعمل و تشغيل البرنامج مرة أخرى.
في الأخير و بعد الإنتهاء من المرور على جميع الملفات نطبع الجملة ' !Done '.
أتمنى أن تكونوا قد استفدتم، نلتقي في مقال آخر إن شاء الله.
للإطلاع على الشيفرة المصدرية النهائية للبرنامج: Source Code
صورة الملفات التي في الصورة من موقع Storyset
التعليقات (1)
أريد أن يتم تنفيذ الأوامر على مجلد سيتم انشاء ملفات فيه مستقبلا ما هي الاكواد
مجلد به ملفات واريد ترتيب الملفات به ترتيبا ابجديا على الشاشة .
لايوجد لديك حساب في عالم البرمجة؟
تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !