قائمة الدليل في Go: من البسيط إلى المعقد
\n\nالعمل مع نظام الملفات هو أحد المهام الأساسية لأي لغة برمجة. في Go، تم تنفيذه بأناقة لدرجة أن حتى العملية الروتينية مثل list directory in Go تتحول إلى مغامرة ممتعة. إذا كنت قد تساءلت يومًا: "كيف يمكنني الحصول على قائمة الملفات في مجلد باستخدام Go؟" فقد وصلت إلى المكان الصحيح. اليوم سنستعرض جميع الطرق الممكنة، من الإخراج البسيط إلى الاجتياز التكراري مع التصفية.
\n\nلماذا هذا الموضوع شائع جدًا على Stack Overflow؟ لأن Go يقدم عدة طرق، واختيار الطريقة الصحيحة هو نصف النجاح. سنناقش الطريقة الكلاسيكية os.ReadDir، والطريقة القديمة ioutil.ReadDir (ولكن لا يزال من الممكن العثور عليها في المشاريع القديمة)، والطريقة القوية filepath.Walk للاجتياز التكراري. هيا بنا!
1. أبسط قائمة: os.ReadDir
\n\nبدءًا من Go 1.16، حصلت حزمة os على طريقة جديدة ReadDir، والتي أصبحت المعيار الفعلي. تقوم بإرجاع شريحة من كائنات os.DirEntry - أوصاف خفيفة الوزن للملفات والمجلدات. إليك كيف يبدو ذلك:
package main\n\nimport (\n "fmt"\n "os"\n "log"\n)\n\nfunc main() {\n // قراءة محتويات الدليل الحالي\n entries, err := os.ReadDir(".")\n if err != nil {\n log.Fatal(err)\n }\n\n fmt.Println("محتويات المجلد الحالي:")\n for _, entry := range entries {\n fmt.Printf("- %s (دليل: %v)\\n", entry.Name(), entry.IsDir())\n }\n}\n\n\nسيقوم هذا الكود بعرض جميع الملفات والمجلدات في الدليل الحالي. لاحظ: os.ReadDir لا يقرأ المجلدات الفرعية - فقط المستوى الأول. إذا كنت بحاجة إلى list directory in Go بشكل تكراري، تابع القراءة.
2. ioutil.ReadDir: قديم ولكنه مألوف
\n\nقبل إصدار Go 1.16، كان الجميع يستخدمون ioutil.ReadDir. يقوم بإرجاع []os.FileInfo - هيكل أثقل يحتوي على معلومات كاملة عن الملف (الحجم، أذونات الوصول، وقت التعديل). على الرغم من أن الطريقة تم وضع علامة عليها كمهملة، إلا أنه لا يزال بإمكانك العثور عليها في الكود القديم:
package main\n\nimport (\n "fmt"\n "io/ioutil"\n "log"\n)\n\nfunc main() {\n files, err := ioutil.ReadDir("./mydir")\n if err != nil {\n log.Fatal(err)\n }\n\n fmt.Println("الملفات في mydir (الطريقة القديمة):")\n for _, file := range files {\n fmt.Printf("الاسم: %s, الحجم: %d بايت\\n", file.Name(), file.Size())\n }\n}\n\n\nالفرق الرئيسي: ioutil.ReadDir يقوم بفرز النتيجة حسب اسم الملف (مثل ls)، بينما os.ReadDir لا يفعل ذلك. إذا كان الترتيب مهمًا، استخدم sort.Slice أو الفرز يدويًا.
3. الاجتياز التكراري باستخدام filepath.Walk
\n\nعندما تحتاج إلى المرور عبر جميع المجلدات الفرعية، تأتي filepath.Walk للإنقاذ. هذه الدالة تجتاز شجرة الدليل، وتستدعي دالة رد لكل عنصر يتم العثور عليه. مثالية للنسخ الاحتياطي، أو البحث عن الملفات، أو تحليل هيكل المشروع:
package main\n\nimport (\n "fmt"\n "os"\n "path/filepath"\n)\n\nfunc main() {\n root := "./myproject"\n err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {\n if err != nil {\n return err\n }\n fmt.Printf("تم العثور على: %s (الحجم: %d)\\n", path, info.Size())\n return nil\n })\n if err != nil {\n fmt.Println("خطأ في الاجتياز:", err)\n }\n}\n\n\nنقطة مهمة: filepath.Walk يتبع الروابط الرمزية وقد يدخل في حلقة لا نهائية إذا كانت هناك روابط دائرية. للإنتاج، استخدم filepath.WalkDir (Go 1.16+) - فهو أخف وأكثر أمانًا.
4. التصفية: ملفات .go فقط أو المجلدات فقط
\n\nغالبًا ما تحتاج إلى الحصول على أنواع معينة فقط من الملفات، وليس كل شيء. دعنا ننفذ التصفية باستخدام strings.HasSuffix والتحقق من IsDir()