سؤال

عندما أقوم بتشغيل تطبيق Java الذي يجب أن يقرأ من ملف في Eclipse ، أحصل على ملف java.io.FileNotFoundException, ، على الرغم من أن الملف في الدليل الصحيح. يمكنني تجميع التطبيق وتشغيله من سطر الأوامر على ما يرام ؛ تحدث المشكلة فقط في Eclipse ، مع أكثر من مشروع وتطبيق. هل هناك إعداد أحتاج إلى تغييره في تكوينات التشغيل أو بناء مسارات للحصول عليه للعثور على الملف بشكل صحيح؟

هل كانت مفيدة؟

المحلول

المشكلة على الأرجح أن تطبيقك يستخدم مسار نسبي. كما يقول Palusc ، يمكن أن تكون أسماء المسارات النسبية مشكلة. لكن IMO ، يذهب بعيدًا جدًا عندما يقول [يجب أبداً استخدم المسارات النسبية في java.io ".

عندما يفتح التطبيق ملفًا باستخدام (على سبيل المثال) FileInputStream(File) مُنشئ ، يتم حل أسماء المسارات النسبية بالنسبة إلى "الدليل الحالي" في عملية موصوفة على النحو التالي في Javadoc for File.getAbsolutePath().

...] وإلا يتم حل اسم المسار هذا بطريقة تعتمد على النظام. على أنظمة UNIX ، يتم جعل اسم المسار النسبي مطلقًا من خلال حله مقابل دليل المستخدم الحالي. على أنظمة Microsoft Windows ، يتم إجراء اسم مسار نسبي مطلقًا عن طريق حله مقابل الدليل الحالي لمحرك الأقراص المسمى بالمسار ، إن وجد ؛ إذا لم يكن كذلك ، يتم حلها مقابل دليل المستخدم الحالي.

لذلك على الفور ، نرى أن فكرة "الدليل الحالي" لها فروق مختلفة على منصات Windows و UNIX. المسألة الثانية هي أنه في جافا الخالصة ، لا يمكنك معرفة الدليل الحالي بشكل نهائي ، وبالتأكيد لا يمكنك تغييره من أجل JVM الحالي باستخدام Java النقي. (عند بدء تشغيل JVM ، يتم تعيين خاصية نظام "user.dir" على الدليل الحالي ، ولكن لا يوجد شيء يمنع طلبًا من تغيير العقار لذلك لا يمكنك الاعتماد عليها تمامًا. علاوة على ذلك ، فإن تغيير "user.dir" يغير فقط الطريقة التي يتم بها حل المسار الفارغ ، وليس المسارات النسبية بشكل عام.)

إذن ماذا يجب أن تفعل حيال هذا؟

  • أحد الخيارات هو استخدام أسماء المسارات المطلقة للإشارة إلى الملفات. هذا موثوق به في (تقريبًا) جميع الحالات ، ولكن يمكن أن يكون استخدام أسماء المسارات المطلقة مشكلة إذا كان على المستخدم إدخال اسم المسار ، أو إذا كنت بحاجة إلى تجنب أسماء المسارات المطلقة (أو المكونة).

  • الخيار الثاني هو استخدام أسماء المسارات النسبية ClassPath وتحديد موقع الملفات المتعلقة بدليل تثبيت التطبيق. هذا يعمل إذا كان هذا هو ما عليك القيام به ، ولكنه يمثل مشكلة إذا كنت بحاجة إلى تمرير أ File إلى بعض طريقة المكتبة. كما أنه لا يساعد إذا كنت تحاول العثور على تفضيلات تطبيق المستخدم. (بشكل عام ، يعد وضع تفضيلات المستخدم في دليل التثبيت خطأ ...)

  • الخيار الثالث هو تسمية ملف بالنسبة إلى بعض الدليل المطلق الذي تحصل عليه من مكان آخر ؛ على سبيل المثال new File(System.getProperty("home.dir"), "foo/bar");.

  • الخيار النهائي هو استخدام أسماء المسارات النسبية ، وافترض أن المستخدم يعرف الدليل الحالي. بالنسبة للعديد من التطبيقات التي يعمل عليها المستخدم من سطر الأوامر ، هذا هو الحل الصحيح.

في حالة معينة من الكسوف ، هناك حل بسيط. انتقل إلى "تكوين التشغيل" الذي تستخدمه لإطلاق التطبيق الخاص بك ، وافتح علامة التبويب "الوسائط" ، وانقر فوق زر الراديو "الآخر". ثم أدخل اسم المسار المطلق كدليل عمل للتطبيق الذي تم إطلاقه. عند إطلاق الطفل JVM ، سيكون له دليل العمل المحدد كدليل الحالي.

نصائح أخرى

خيار آخر هو ببساطة معرفة الدليل الذي يشير إليه "المسار الحالي" في بيئتك - مهما كان ذلك. بمجرد معرفة ذلك ، يمكنك اختيار الحل الخاص بك من هناك. ربما هذا هو استخدام المسار النسبي المناسب لموقع ملفك أو نقل الملف.

    File testFile = new File("");
    String currentPath = testFile.getAbsolutePath();
    System.out.println("current path is: " + currentPath);

عند إنشاء تطبيق Java افتراضي في Eclipse ، تحصل على بنية الدليل هذه:

./اسم المشروع/ - دليل الجذر
./projectname/bin/ - دليل الإخراج ، يحتوي على ملفات .class
./projectname/SRC/ - دليل المصدر ، يحتوي على ملفات .java

إذا طلبت التطبيق الخاص بك "./data.txt" ، فسيبحث عنه بالنسبة إلى دليل الجذر. هذا هو "دليل العمل" ويمكن تكوينه في علامة تبويب الوسائط وفقًا لرد مارتن أعلاه.

أنت تقول إنه يعمل من سطر الأوامر؟ هذا على الأرجح لأنك داخل مجلدات Bin أو SRC عند تشغيل Java Binary. دليل العمل في هذه الحالة هو أي دليل على موجه الأوامر موجود حاليًا في الداخل. إذا ، على سبيل المثال ، تذهب إلى / src / الدليل ، على سبيل المثال javac *.java ثم قم بتشغيل الملفات من هناك ، وسوف يبحث عن "./data.txt" داخل/src/directory. إذا ذهبت داخل / bin / directory وقمت بتشغيل التطبيق الخاص بك من هناك ، فسيبحث عن الملف بالنسبة إلى / bin / directory.

يجب أبداً استخدم المسارات النسبية في java.io أمور. سيصبح المسار يعتمد على دليل العمل الحالي ، والذي يعتمد على الطريقة التي بدأت بها التطبيق ، وبالتالي فهي ليست في جميع البيئات. هذا لا يمكن السيطرة عليه من داخل تطبيق Java. مشكلة قابلية النقل! دائما استخدام المسارات المطلقة. وهكذا على سبيل المثال c:/path/to/file.ext أو /path/to/file.ext (مع القطع المائلة الرائدة) لـ UNIX و CONSORTS (أو حتى Windows عندما يكون خطاب القرص غير ذي صلة).

كلما ترغب في شحن بعض الملفات إلى جانب تطبيقك ، تتمثل الممارسة الشائعة في وضعها في classpath كذلك. بهذه الطريقة يمكنك فقط استخدامها ClassLoader#getResource() للحصول على موقعها. يعود URL. يمكنك استخدام URL#toURI() أو URL#getPath() وتمريره إلى مُنشئ java.io.File ثم استخدمه أكثر بالطريقة المعتادة.

في مشروع Eclipse الخاص بك ، src المجلد (حيث يذهب مصدر Java الخاص بك) هو في الأساس جذر classpath. علاوة على ذلك ، فإنه يغطي أيضًا جميع المشاريع الأخرى والمجلدات (الخارجية) التي يتم أخذها في المشروع مسار بناء.

على افتراض أنك وضعت ملف معين في جذر من classpath:

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL url = classLoader.getResource("file.ext");
File file = new File(url.getPath());
FileInputStream input = new FileInputStream(file);
// ...

يمكنك حتى استخدام ClassLoader#getResourceAsStream() للحصول مباشرة InputStream:

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream input = classLoader.getResourceAsStream("file.ext");
// ...

إذا تم وضعها داخل الحزمة ، فيمكنك فقط استخدام أسماء المسارات المعتادة:

URL url = classLoader.getResource("com/example/file.ext");
// ...

أو

InputStream input = classLoader.getResourceAsStream("com/example/file.ext");
// ...

كنت أواجه مشكلة مماثلة ، وضعت ملفاتي في مجلد يدعى cobolcopybooks داخل مجلد SRC وحاولت الوصول إليها داخل مشروعي باستخدام classloader.getResource ("cobolcopybooks/demostud.cob") لكنني كنت أحصل على استثناء مؤشر خالية ، أنا جربته عدة مرات من خلال تنظيف وإنشاء مساحات العمل بعد عدة محاولات فاشلة أدركت أنني لم أكن أعشق المشروع للسماح للملفات بالبناء مع المشروع. أي يجب أن تكون هذه الملفات مرئية مع ملفات الفصول الدراسية الأخرى كما هو الحال في وقت التشغيل ، وسيكون دليل الجذر هو دليل bin ويبحث عن تلك الملفات هناك.

على افتراض أن المستخدم لا يدخل مسار الملف الكامل إلى الملف وإدخال شيء مثل "myfilenameonly".File file = new File(".", args[0]) ضروري في هذه الحالة لتحديد موقع الملف (الاهتمام بالوسيطة الأولى التي تم تمريرها).

جميع المنصات: File.getParent() لا يعيد الدليل الأصل ، يجب أن يعود ".." أو اسم الدليل الأصل بطريقة محددة لنظام الملفات.

إذا قمت بإنشاء ملف "myfilenameOnly" دون تحديد المسار الكامل للدليل الذي يقع فيه ، File.getParent(), ، على سبيل المثال ، سيعود فارغة.

انظر كذلك: http://bugs.sun.com/bugdatabase/view_bug.do؟bug_id=1228537

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top