برنامج بلغة بايثون لتنظيم الملفات.
كيف تُبرمج سكريبت بايثون يقوم بتنظيم ملفات مُجلد ما بدلا عنك؟.
المقدمة:
لربما لديك مجلد تضع به كل أنواع الملفات من فيديوهات و صور إلى ملفات مضغوطة و غيرها، و كل مرة تخبر نفسك أنك ستقوم بتنظيمه لكن لما ترى تلك الفوضى تتهرب و تُبقيه على ذاك الحال، حسنا أتفق معك في هذا خاصة و لو كان مجلدك به أكثر من 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)
![](https://3alam.pro/img/avatars/avatar15.jpg)
أريد أن يتم تنفيذ الأوامر على مجلد سيتم انشاء ملفات فيه مستقبلا ما هي الاكواد
مجلد به ملفات واريد ترتيب الملفات به ترتيبا ابجديا على الشاشة .
لايوجد لديك حساب في عالم البرمجة؟
تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !