أين أنا؟ أو كيف لا تضيع في نظام الملفات لتطبيق Java
\n\nكل مطور Java سأل نفسه مرة واحدة على الأقل: "أين، بالضبط، يتم تنفيذ الكود الخاص بي؟" يبدو أنك تشغل البرنامج من IDE، وكل شيء يعمل. ولكن بمجرد نقله إلى خادم أو حاوية Docker - الملفات التي كان من المفترض أن تكون بجانب ملف jar، تجد نفسها في مكان ما في أعماق /opt/app أو /tmp. هل هذا الموقف مألوف؟
سؤال "How to get the current working directory in Java?" هو أحد أكثر الأسئلة شيوعًا على Stack Overflow. وليس من دون سبب: الإجابة تبدو واضحة، ولكنها في الواقع تخفي العديد من المزالق. في هذه المقالة، سنشرح أفضل الممارسات لعام 2025: كيفية الحصول على current working directory بشكل موثوق، ومتى يمكن الوثوق به، ومتى يكون من الأفضل البحث عن بدائل.
\n\nإخلاء مسؤولية: المقالة مكتوبة لـ Java 17+ (LTS)، لكن الأمثلة متوافقة مع Java 11 والإصدارات الأحدث. إذا كنت لا تزال تستخدم Java 8 - قم بالتحديث فورًا، لكن الكود سيعمل أيضًا.\n\n
الطريقة التقليدية: System.getProperty("user.dir")
\n\nأبسط وأكثر طريقة مستخدمة على نطاق واسع هي الوصول إلى خاصية النظام user.dir. هذا ما ستراه في 90% من الإجابات على Stack Overflow:
public class WorkingDirectoryExample {\n public static void main(String[] args) {\n String cwd = System.getProperty("user.dir");\n System.out.println("الدليل الحالي: " + cwd);\n }\n}\n\nماذا ستحصل على المخرجات؟ المسار إلى المجلد الذي تم تشغيل JVM منه. إذا قمت بالتشغيل من جذر المشروع - سيكون /Users/you/projects/my-app. إذا قمت بالتشغيل من target/ - سيكون target/.
لماذا هذا ليس موثوقًا دائمًا؟
\n\nالمشكلة رقم 1: IDE وأنظمة البناء تخدع. IntelliJ IDEA بشكل افتراضي يضبط working directory على جذر الوحدة. Maven - على جذر المشروع. Gradle - على جذر الوحدة. ولكن يمكن تغيير ذلك في إعدادات التشغيل. ونتيجة لذلك، يعمل الكود على الجهاز المحلي، ولكن على الخادم - لا.
\n\nالمشكلة رقم 2: اختبارات الوحدة. عند التشغيل عبر JUnit أو TestNG، قد يكون working directory هو جذر المشروع، أو قد يكون مجلد البناء. يعتمد ذلك على إعدادات المُشغّل.
\n\nالمشكلة رقم 3: تطبيقات الويب والخدمات المصغرة. في الحاويات (Tomcat, Jetty)، غالبًا ما يكون working directory مساويًا لـ $CATALINA_HOME/bin أو /. لا علاقة لهذا بملف WAR الخاص بك.
النهج الحديث: java.nio.file.Paths
\n\nبدءًا من Java 7، لدينا طريقة أكثر "جافاوية" - عبر NIO.2 API:
\n\nimport java.nio.file.Paths;\n\npublic class NioWorkingDirectory {\n public static void main(String[] args) {\n String cwd = Paths.get("").toAbsolutePath().toString();\n System.out.println("الدليل الحالي (NIO): " + cwd);\n }\n}\n\nماذا يحدث هنا؟ Paths.get("") ينشئ مرجعًا لمسار فارغ، والذي يتم تفسيره على أنه مسار نسبي إلى الدليل الحالي. الطريقة toAbsolutePath() تحوله إلى مسار مطلق. النتيجة - نفس user.dir، ولكن مع كتابة أكثر صرامة.
المزايا:
\n- \n
- يعمل مع كائنات
Path، وليس مع سلاسل نصية (أخطاء أقل مع الفواصل) \n - يمكن استخدامه فورًا في APIs الحديثة \n
- متعدد المنصات (Windows vs Linux) \n
العيوب: كلها نفسها - لا يزال هذا هو working directory للعملية.
\n\nالبديل: File("")
\n\nلمن لا يريد الانتقال إلى NIO (على الرغم من أنه خطأ):
\n\nimport java.io.File;\n\npublic class FileWorkingDirectory {\n public static void main(String[] args) {\n String cwd = new File("").getAbsolutePath();\n System.out.println("الدليل الحالي (File): " + cwd);\n }\n}\n\nنفس الشيء تمامًا مثل Paths.get("").toAbsolutePa