العمل مع المجلدات
العمل مع المجلدات
المجلدات هي الهيكل العظمي لأي نظام ملفات. تمنحك واجهة NIO.2 في جافا — المرتكزة على java.nio.file.Files وjava.nio.file.Path — تحكمًا دقيقًا وتعبيريًا في إنشاء المجلدات وسرد محتوياتها والمشي عبر شجرة المجلدات بالكامل. في هذا الدرس ستتعلم بالضبط أي دالة تستخدم ولماذا اتُّخِذ كل قرار تصميمي.
إنشاء المجلدات
توفّر NIO.2 دالتَي بناء متمايزتَين، واختيار الخاطئة منهما خطأ شائع.
Files.createDirectory(Path) تُنشئ مجلدًا واحدًا بالضبط. تفشل الدالة بإطلاق NoSuchFileException إن لم يكن أيٌّ من المجلدات الأب موجودًا، وبـ FileAlreadyExistsException إن كان المجلد الهدف نفسه موجودًا.
Files.createDirectories(Path) تُنشئ المسار كاملًا — بما فيه المجلدات الأب — وهي idempotent: إن كان المجلد موجودًا بالفعل تعود بصمت بدلًا من إطلاق استثناء.
createDirectories في كود التطبيق. نادرًا ما تعرف التطبيقات الحقيقية مسبقًا إن كان المجلد الأب موجودًا. استخدام createDirectories يُلغي الحاجة للتحقق المسبق من الوجود وهو آمن من ناحية سباق الخيوط — فالتحقق والإنشاء يحدثان ذريًا على مستوى نظام التشغيل.
يمكنك أيضًا إنشاء مجلد بصلاحيات POSIX محددة في استدعاء واحد:
سرد مدخلات المجلد
ثلاث دوال موجودة لسرد محتويات المجلد. تتباين في العمق، والكسل، والتحكم الذي تمنحه.
Files.list(Path) تُعيد Stream<Path> كسولًا للأبناء المباشرين فقط (عمق 1). لأن الدفق مدعوم بمكرّر مجلد يجب إغلاقه — استخدم دائمًا try-with-resources.
Files.list وFiles.walk وFiles.find.
Files.newDirectoryStream(Path) وصيغتها مع الـ glob تمنحانك DirectoryStream<Path> — مفيدة حين تريد فلترة نمط glob يعالجها نظام التشغيل بدلًا من جافا:
المشي عبر شجرة المجلدات
Files.walk(Path, int maxDepth) تُعيد Stream<Path> كسولًا يُنفّذ اجتيازًا بالعمق أولًا. الجذر نفسه دائمًا هو أول عنصر يُنبعث.
حذف maxDepth يمشي الشجرة بالكامل؛ تحديده يُحدّد العودية. عمق 1 يعادل Files.list.
Files.find(Path, int maxDepth, BiPredicate<Path, BasicFileAttributes>) هو الابن الأقوى. يستقبل المسند كلًا من المسار ولقطة BasicFileAttributes الخاصة به، فتستطيع الفلترة على البيانات الوصفية (الحجم، آخر تعديل، هل هو رابط رمزي) دون استدعاء نظام إضافي لكل مدخل:
Files.find أفضل من Files.walk مع Files.readAttributes. كل استدعاء لـ Files.readAttributes هو استدعاء نظام منفصل. Files.find تلتقط البيانات الوصفية في نفس استدعاء النظام الذي يقرأ مدخلة المجلد، فتدفع مرة واحدة لا مرتين.
حذف شجرة مجلدات
يجب أن تكون المجلدات فارغة قبل أن يقبلها Files.delete(Path). لحذف شجرة بشكل تكراري، امشِ فيها بترتيب من الأسفل إلى الأعلى عبر عكس دفق مُرتَّب:
Files.delete دائمة. في كود الإنتاج تحقق من مسار الجذر بعناية قبل التكرار. متغير في المكان الخطأ يمكنه حذف أدلة مشاريع كاملة.
نسخ وتحريك أشجار المجلدات
Files.copy تنسخ مدخلة واحدة؛ ولا تتكرر. لنسخ شجرة بأكملها، امشِ فيها وأعد إنتاج البنية يدويًا:
الأسلوب المفتاحي هنا هو dest.resolve(src.relativize(source)): يجرّد بادئة الجذر المصدري ويلصق كل جزء متبقٍّ بجذر الوجهة — منتجًا المسار المعكوس دون تلاعب بالنصوص.
الخلاصة
- استخدم
Files.createDirectoriesفي معظم الحالات — فهي idempotent وتُنشئ المجلدات الأب. - استخدم
Files.listللسرد الضحل والكسول؛ أغلق الدفق دائمًا. - استخدم
Files.walkللاجتياز التكراري وFiles.findحين تحتاج فلترة مبنية على البيانات الوصفية في نفس التمريرة. - احذف الأشجار من الأسفل إلى الأعلى بعكس دفق مُرتَّب؛ انسخ الأشجار بالمشي وحل المسارات النسبية.