لماذا أصبح سؤال "إنشاء مجلد إذا لم يكن موجودًا" ميمًا في C#
\n\nإذا كنت قد كتبت أي كود يقوم بحفظ الملفات، أو معالجة التقارير، أو تخزين البيانات مؤقتًا، فمن المحتمل أنك واجهت موقفًا: "ماذا لو كان المجلد غير موجود؟". قد يبدو الأمر بسيطًا؟ تتحقق - ثم تنشئ. لكن في الممارسة العملية، تتحول هذه المهمة إلى مغامرة حقيقية مليئة بالأخطاء والبطء والاستثناءات.
\n\nعلى Stack Overflow، حصد سؤال "If a folder does not exist, create it" مئات الآلاف من المشاهدات. وهذا ليس من قبيل الصدفة. حتى المطورون ذوو الخبرة يكتبون أحيانًا كودًا يبدو أنه يعمل، لكنه يقتل الأداء أو يفشل في السيناريوهات متعددة الخيوط.
\n\nفي هذه المقالة، سنناقش كيفية إنشاء مجلد بشكل صحيح في C# إذا لم يكن موجودًا دون الوقوع في الأخطاء. ستتعلم لماذا Directory.CreateDirectory ليس مجرد "إنشاء"، بل أداة قوية للتحسين، وكيفية كتابة كود لا يبطئ حتى على الأقراص البطيئة.
النهج الأكثر شيوعًا (والخاطئ)
\n\nعندما يواجه المبتدئ هذه المهمة لأول مرة، عادةً ما يكتب شيئًا مثل:
\n\nif (!Directory.Exists(path))\n{\n Directory.CreateDirectory(path);\n}\n\n\nللوهلة الأولى - يبدو منطقيًا. تحقق من عدم وجود المجلد، ثم أنشئه. لكن دعنا نرى ما يحدث تحت الغطاء.
\n\nالمشكلة رقم 1: استدعاء مزدوج لنظام الملفات
\nDirectory.Exists يقوم باستعلام لنظام الملفات. Directory.CreateDirectory يقوم باستعلام آخر (أو عدة استعلامات). في النهاية، نصل إلى القرص مرتين. على SSD هذا ليس حرجًا، لكن على المجلدات الشبكية أو الأقراص الصلبة البطيئة (HDD)، كل عملية إضافية تعني فقدان ميلي ثانية. وماذا لو كان هناك مئات من هذه التحققات؟
المشكلة رقم 2: حالة السباق (race condition)
\nتخيل أن خيطين (threads) ينفذان هذا الكود في نفس الوقت. كلاهما يتحقق - المجلد غير موجود. كلاهما يحاول الإنشاء. أحدهما ينشئ بنجاح، والثاني يفشل مع IOException ("المجلد موجود بالفعل"). أو ما هو أسوأ، كلاهما ينشئ، لكن أحدهما يعيد كتابة صلاحيات الوصول التي حددها الآخر.
المشكلة رقم 3: شعور زائف بالأمان
\nيعتقد الكثيرون: "لقد تحققت - إذن كل شيء على ما يرام". لكن بين التحقق والإنشاء قد تمر ميكروثانية، يمكن خلالها لعملية أخرى إنشاء هذا المجلد. أو قد يحجب برنامج مكافحة الفيروسات الإنشاء. أو قد تنفد المساحة على القرص.
\n\nالنهج الصحيح: Directory.CreateDirectory - صديقك
\n\nوالآن المفاجأة: توثيق Microsoft يقول مباشرة أن Directory.CreateDirectory يتحقق بنفسه من وجود المجلد. إذا كان موجودًا - لا يفعل شيئًا (يعيد كائن DirectoryInfo للمجلد الموجود). إذا لم يكن موجودًا - ينشئه.
أي أن الكتلة الكاملة مع if غير ضرورية! يكفي فقط:
Directory.CreateDirectory(path);\n\n\nهذا ليس فقط أقصر، بل أفضل في الأداء و أكثر أمانًا في البيئات متعددة الخيوط. الطريقة ذرية من وجهة نظر نظام الملفات: إما أن تنشئ المجلد، أو تتأكد من وجوده بالفعل، وتعيد التحكم.
\n\nلماذا هذا أسرع؟
\nلأنه داخل CreateDirectory يتم استخدام دالة WinAPI CreateDirectory، والتي في حالة وجود المجلد تعيد ببساطة ERROR_ALREADY_EXISTS. لا اجتياز إضافي للدليل. استدعاء نظام واحد بدلاً من اثنين.
غوص عميق: كيف يعمل Directory.CreateDirectory
\n\nدعنا نلقي نظرة على الكود الحقيقي. الطريقة لا تنشئ المجلد النهائي فقط، بل جميع الدلائل الأصلية (parent directories) في المسار. هذا سبب آخر لعدم كتابة منطقك الخاص.
\n\nstring path = @"C:\\Projects\\Reports\\2025\\January\\Data";\nDirectory.CreateDirectory(path);\n// إذا كان C:\\Projects غير موجود - سينشئه.\n// إذا كان Reports غير موجود - سينشئه.\n// وهكذا، حتى Data.\n\n\nبدون هذا، كان عليك تقسيم المسار بشكل متكرر وإنشاء