كيف تستخدم البرمجة في حل المشكلات التي تواجهك مع الملفات

01-09-2013 C-Sharp | Programming
إعلان

فكرت في إعادة كتابة إسمي مرة أخرى بخط مختلف فكلمة محمد جمال في الأعلى بهذا الخط لا تعجبني, قمت بالبحث عن مجموعة خطوط لعلها تسعفني في هذا الأمر, والحمدلله وجدت تشكيله كبيره من الخطوط بحجم 18.4 ميجابيت تحتوي على مجموعة خطوط عربية رائعة, وكالعادة جهزت نفسي لأقوم بفك ضغط الملف وتضليل كافة ملفات الخطوط ونسخها إلى مجلد الخطوط "Fonts" في النظام ولكن إعتقاداتي لم تكن دقيقة !

allfiles

المشكلة ! ظهرت لي مجموعة من المجلدات في ظاهرها منسقه جدا وتحمل بين طياتها العديد من العمل لأقوم به, كل مجلد من هذه المجلدات يتضمن مجلد فرعي, والمجلد الفرعي يتضمن مجلد فرعي اخر, وإذا حالفك الحظ فستجد ملف الخطوط مباشرة داخل هذا المجلد, وإذا لم يحالفك فستجد أيضا مجموعة من المجلدات الفرعية, كانت أشبه بمتاهه !

هل حقا يتوجب علي الدخول إلى كل مجلد لأقوم بنسخ محتوياته ! هل سأقوم بتبديد أكثر من 20 دقيقة في عمل روتيني ممل وأبقى طوال الوقت أتضرع إلى الله عل هذه المجلدات تنقص أو يتلاشى بعضها لكي أنهي هذا العمل بسرعة ؟ بالتأكيد لن أقوم بكل هذا العمل.

كالعادة فتحت علبة السجائر وأشعلت واحدة مع إرتشاف القهوة "الساده" وبعدها قمت باستدعاء صديقي الوفي Visual Studio وأنشأت مشروع جديد "Windows Forms Application"

wfa

وبعد أن أصبح المشروع جاهزا لأقوم بكتابة الكود قمت بإستدعاء IO namespace التي تحتوي على عدد كبير من الفئات "classes" ومنها ما هو مختص بالتعامل مع الملفات والمجلدات.

ionamespace

بعدها قمت بنسخ ملف الخطوط الرئيسي إلى جزء D وأعدت تسميته ليصبح Fonts ومن ثم قمت بكتابة برنامج بسرعة لأشعر بالفرق بين إستخدام البرنامج لتنفيذ المهمة وتنفيذها بشكل يدوي, وهذا ما قمت بكتابته.

String MasterDirectory = "D:\\Fonts";
String dName = "D:\\NewFontFolder"; // Move fonts to this folder 
DirectoryInfo _info = new DirectoryInfo(dName); 
if (_info.Exists == false) // check if the directory exist or not 
      Directory.CreateDirectory(dName); //if not exist this will create it 

List<String> fontFile = Directory.GetFiles(MasterDirectory, "*tf*", SearchOption.AllDirectories).ToList();
            //set searchoption alldirectory to search in all subdirectories 

foreach (String file in fontFile) //loop to move all files 
{
      FileInfo currentfile = new FileInfo(file); //object to communicate with each file 
      //check if the file exist by name or not 
      if (new FileInfo(_info + "\\" + currentfile.Name).Exists == false) 
            currentfile.MoveTo(_info + "\\" + currentfile.Name);//if not exist, move
}

النتيجة

result

النتائج كانت مرضية جدا, قمت بتقليص أكثر من 20 دقيقة ممله إلى بضعة دقائق برمجية ممتعة, ولكن ما المهمه التي قامت بها الأسطر في الأعلى ؟ سأقوم بالتحدث عن البرنامج قليلا ليتسنى للبعض حل مثل هذه المشاكل بطريقة ممتعة.

أولا قمت بتحديد أسماء المجلدات التي أقوم بالعمل عليها ووضعها في متغيرات نصية "String" يسهل الوصول لها وتعديلها لاحقا, MasterDirectory هو مجلد الخطوط الرئيسي وسأطلق عليه "المجلد الرئيسي", أما dName فهو المجلد الذي ستجتمع فيه ملفات الخطوط بعد معالجتها وسأطلق عليه "المجلد الثانوي".

string MasterDirectory = "D:\\Fonts";
String dName = "D:\\NewFontFolder";

قمت بعدها بإنشاء كائن "object" من DirectoryInfo class للتعامل مع المجلدات وقمت بإعطائها إسم المجلد الثانوي dName لكي أقوم بإجراء العمليات عليه.

DirectoryInfo _info = new DirectoryInfo(dName);

الان نقوم بالتأكد إذا كان المجلد الثانوي موجود مسبقا أم لا, إذا لم يكن موجود نقوم بإنشائه, الداله Exists تقوم بإرجاع true إذا كان المجلد موجودا و false إذا لم يكن موجودا, الدالة CreateDirectory تقوم بإنشاء المجلد.

if (_info.Exists == false) // check if the directory exist or not 
       Directory.CreateDirectory(dName); //if not exist this will create it 

هذا السطر للبحث في كافة المجلدات والمجلدات الفرعية عن الملفات التي تنتهي بالحرفين tf وهي الملفات الخاصه بالخطوط وإمتدادها يكون إما ttf أو otf, القيم التي ترجع من تنفيذ الدالة GetFiles هي أسماء كافة الملفات التي تتطابق عليها شروط البحث على شكل List تتكون عناصرها من متغيرات نصيه, نقوم بتخزينها في object من نفس النوع "List" يحتوي على objects من نوع String.

الدالة GetFiles تحتاج إلى مجموعة من المعلومات Parameters 

Directory.GetFiles(DirectoryToSearch,searchPattern,searchOption);
  1. DirectoryToSearch : المجلد الذي ستجري بداخله عملية البحث عن الملفات.
  2. searchPattern : نمط الملفات التي ترغب بالبحث عنها
  3. searchOption : نستخدم searchOption.AllDirectories للبحث داخل كافة المجلدات الفرعية.
List<String> fontFile = Directory.GetFiles(MasterDirectory, "*tf*", SearchOption.AllDirectories).ToList();

لتتعرف أكثر على فئة List أنصحك بقراءه هذا الشرح.

الان وبعد أن حصلنا على List بأسماء الملفات "الخطوط" التي سنقوم بنقلها إلى المجلد الثانوي سنقوم بإجراء جملة دوران "foreach loop" على كافة عناصر List, ستمكننا جملة الدوران من معالجة ونقل كل عنصر بشكل منفرد.

من مميزات جملة الدوران "foreach" هي انك لا تحتاج إلى معرفة عدد العناصر في القائمة, كل ما عليك فعله هو إعطائها القائمة التي تريد تنفيذ جملة الدوران عليها ونوع العناصر في القائمة, وفي برنامجنا قمنا بتعريف عناصر القائمة من "String", يمكنك معرفة ذلك عن طريق السطر الذي قمنا من خلاله بتعريف القائمة <List<String.

بعد الحصول على List كاملة يمكننا الان عمل جملة دوران على كافة العناصر الموجوده بها لنأخذ قيمة كل عنصر ونضعها في المتغير file لتتم معالجته بشكل مستقل 

foreach (string file in fontFile)

عند أول دوران تقوم به جملة foreach ستكون قيمة المتغير file هي قيمة العنصر الأول من عناصر القائمة, وفي المرة الثانية تصبح قيمتها مساوية لقيمة العنصر الثاني وهكذا إلى أن تنتهي جميع العناصر.

نقوم الان بإنشاء كائن من الفئة FileInfo التي تمتلك مجموعة من الدوال "Functions" للتعامل مع الملفات, ما يهمنا في الوقت الحالي دالة "MoveTo" التي تقوم بنقل الملفات من مجلد إلى مجلد.

الدالة MoveTo هي مكافئة لعملية القص واللصق, لذلك كن حذرا من إستخدامها في المرحلة التجريبية للبرنامج مع الملفات المهمة, أو الملفات التي لا تملك منها سوى نسخة واحدة.

تماما كما فعلنا عندما حددنا المجلد المطلوب في الفئة DirectoryInfo نقوم بنفس العمل لتحديد الملف المطلوب 

FileInfo currentfile = new FileInfo(file); 

كما قلنا سابقا المتغير file يحتوي على أسم الملف الأول في المصفوفة, وبذلك نستطيع إجراء العمليات على الملف من خلال الكائن currentfile الذي يحتوي على مجموعة من الدوال منها "MoveTo", ولكن ماذا سيحدث إذا كان هناك ملف اخر في المجلد الثانوي بنفس الأسم ؟ 

عند تعريف كائن من فئه معينه "Object From Class", فإن الكائن يرث مجموعة من الصفات المحددة "Functions & Attributes", وفي مثالنا قمنا بتعريف الكائن currentfile من الفئه FileInfo أي أن معظم الدوال الموجودة في الفئة Fileinfo يمكن الوصول إليها من خلال الكائن currentfile, يمكنك معرفة المزيد عن Classes & Objects من خلال هذا الرابط.

مثل هذه الأمور محتمل حدوثها ولكي نجتنب المشاكل هنا نقوم بالتأكد قبل نقل الملف إذا كان هناك ملف اخر بنفس الإسم أم لا, نقوم بالتأكد من ذلك عن طريق الداله Exists.

if (new FileInfo(_info + "\\" + currentfile.Name).Exists == false)

الدالة Exists تقوم بإرجاع قيمة true  إذا كان الملف موجودا وقيمة false  إذا لم يكن موجودا ولكن في المثال السابق قمنا بمقارنة القيمة التي تقوم بإرجاعها الدالة Exists بقيمة false, وبالتالي ستنعكس قيمة التعبير, فإذا كان الملف موجودا فسيرجع التعبير قيمة false, وإذا لم يكن موجودا فسيرجع القيمة true.

 بعد أن قمنا بالتأكد من عدم وجود ملفات بنفس الأسم نقوم بنقل الملف إلى المجلد الثانوي

currentfile.MoveTo(_info + "\\" + currentfile.Name);

انتهى ! الان يمكنك التعديل عليه ليتناسب مع حاجتك, فأنت تعرف كيف تنشئ searchPattern لتحديد الملفات التي تبحث عنها, كما يمكنك تحديد مجلدات البحث searchOption, وتعرفت إلى جملة الدوران foreach, وتعرف جيدا كيف تستخدم الدالة MoveTo في نقل الملفات.

هذا البرنامج لإستخدامك الشخصي فقط ولا يستطيع أي شخص أن يقوم بإستخدامه, يمكنك إجراء بعض التطويرات على البرنامج ليكون سهل الإستخدام, قم بإضافة FolderBrowserDialog لتختار مجلد البحث, وقم بإضافة اخر لتحديد المكان الذي ترغب بنقل الملفات إليه, قم بوضع Combobox لتحدد خيارات البحث في المجلد "searchOption", وقم أيضا بوضع حقل من نوع Textbox لتحديد نمط البحث "searchPattern", ودعني أرى النتائج, سأكون سعيدا بها ! 

عن محمد جمال

مهندس حاسوب ومطور برمجيات, أعمل Freelancer في تطوير تطبيقات الويب من خلال ASP.NET منذ عام 2007 قمت بإنشاء عدة مشاريع في مجالات مختلفة (المتحكمات الدقيقة, الأنظمة المضمنة, الروبوت, برامج سطح المكتب, أنظمة قواعد البيانات) ومن هواياتي الخط العربي

subscribe

إعلان
إعلان

تنويه : الأراء في هذا الموقع شخصية ولا تبت لأحد بصلة تحت أي حال من الأحوال