Когда я запускаю приложение Java, которое следует читать из файла в Eclipse, я получаю java.io.FileNotFoundException
, хотя файл находится в правильном каталоге. Я могу легко скомпилировать и запустить приложение из командной строки; проблема возникает только в Eclipse, с несколькими проектами и приложениями. Есть ли параметр, который мне нужно изменить в конфигурациях запуска или построить пути, чтобы заставить его правильно найти файл?Java не может найти файл при работе через Eclipse
ответ
Проблема заключается в том, что, скорее всего, ваше приложение использует относительный путь к файлу. Как говорит @BalusC, относительные пути могут быть проблематичными. Но ИМО, он идет слишком далеко, когда говорит «[y] ou should never использовать относительные пути в java.io stuff».
Когда приложение открывает файл, используя (например) конструктор FileInputStream(File)
, относительные пути уничтожаются относительно «текущего каталога» в процессе, описанном ниже в javadoc для File.getAbsolutePath()
.
[...] В противном случае это имя пути будет разрешено зависящим от системы образом. В системах UNIX относительный путь становится абсолютным, разрешая его против текущего каталога пользователя. В системах Microsoft Windows относительный путь становится абсолютным, разрешая его против текущего каталога диска, названного именем пути, если таковой имеется; если нет, он разрешен в отношении текущего каталога пользователя.
Итак, мы сразу видим, что понятие «текущий каталог» имеет разные нюансы на платформах Windows и UNIX. Вторая проблема заключается в том, что в чистой Java вы не можете окончательно узнать, что такое текущий каталог, и вы, конечно же, не можете изменить его для текущей JVM с использованием чистой Java. (Когда запускается JVM, системное свойство «user.dir» устанавливается в текущий каталог, но ничего не останавливает приложение от изменения свойства, поэтому вы не можете полностью полагаться на него. Кроме того, изменение «user.dir» только изменяет способ устранения пустого пути, а не относительные пути в целом.)
Итак, что вы должны сделать по этому поводу?
Один из вариантов - использовать абсолютные пути для обращения к файлам. Это надежное (почти) все случаи, но использование абсолютных путей может быть проблематичным, если пользователь должен ввести путь, или , если вам нужно избегать абсолютных путей пути (или настроенных).
Второй вариант - использовать относительные пути пути classpath и находить файлы относительно каталога установки приложения. Это работает, если это то, что вам нужно сделать, но представляет проблему, если вам нужно передать
File
в какой-либо библиотечный метод. Это также не помогает, если вы пытаетесь найти настройки приложения пользователя. (В общем, внесение предпочтений пользователя в каталог установки является ошибкой ...)Третья опция - указать файл относительно некоторого абсолютного каталога, который вы получаете откуда-то еще; например
new File(System.getProperty("home.dir"), "foo/bar");
.Окончательный вариант - использовать относительные пути и предполагать, что пользователь знает, что представляет собой текущий каталог. Для многих приложений, которые пользователь запускает из командной строки, это правильное решение.
В частном случае Eclipse существует простое решение. Перейдите в «конфигурацию запуска», которую вы используете для запуска приложения, откройте вкладку «Аргументы» и нажмите переключатель «Другой». Затем введите абсолютное имя пути как рабочий каталог для запущенного приложения. Когда дочерний JVM запущен, он будет иметь указанный рабочий каталог в качестве его текущего каталога.
Спасибо за помощь! – derekerdmann
У меня возникла проблема с запуском моего приложения из eclipse, неспособным прочитать файл свойств, который был в корне моего проекта.После того, как я попытался настроить рабочий каталог в конфигурации запуска на $ {workspace_loc}/myproject/bin, он сработал !. – Krishnaraj
@ Кришнарай - Вот что я сказал в последнем абзаце моего ответа :-) –
При создании приложения Java по умолчанию в Eclipse, вы получите эту структуру каталогов:
./ProjectName/ - корневой каталог
./ProjectName/bin/ - выходной каталог, содержащий .class файлы
./ProjectName/src/ - каталог источник, содержащий файлы .java
Если приложение запрашивает «./data.txt» будет искать его по отношению к корневому каталогу. Это «рабочий каталог» и может быть настроен на вкладке «Параметры» в соответствии с ответом Мартина выше.
Вы говорите, что это работает из командной строки? Вероятно, это связано с тем, что вы работаете в папке bin или src при запуске java-двоичного файла. Рабочий каталог в этом случае - это тот каталог, в котором сейчас находится командная строка. Если, например, вы заходите в каталог/src /, скажем javac *.java
, тогда запустите файлы оттуда, он будет искать «./data.txt» в каталоге/src /. Если вы заходите в каталог/bin/и запускаете приложение там, он будет искать файл относительно каталога/bin /.
Спасибо за помощь. Текстовые файлы, которые мне нужны, существуют в каталоге/bin /, поэтому это не проблема. Я буду играть с относительными путями и посмотреть, что я могу получить. – derekerdmann
Вы должны Никогда использовать относительные пути в java.io
. Путь будет зависеть от текущего рабочего каталога, который зависит от способа запуска приложения и, таким образом, не является таким же во всех средах. Это неконтролируемо изнутри приложения Java. Проблемы с переносимостью! Всегда используйте абсолютные пути. Так, например, c:/path/to/file.ext
или /path/to/file.ext
(с ведущей косой чертой) для UNIX и супругов (или даже Windows, когда буква диска не имеет значения).
Всякий раз, когда вы хотите отправить несколько файлов вместе с вашим приложением, распространять практику следует поместить их в classpath. Таким образом вы можете просто использовать ClassLoader#getResource()
, чтобы получить его местоположение. Он возвращает URL
. Вы можете использовать URL#toURI()
или URL#getPath()
и передать его конструктору java.io.File
, а затем использовать его обычным способом.
В вашем проекте Eclipse папка src
(где находится ваш источник Java) является в основном корнем пути к классам. Далее он, конечно же, охватывает все другие проекты и (внешние) папки, которые взяты в проекте Путь сборки.
Предполагая, что вы поместили конкретный файл в корень из пути к классам:
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");
// ...
приложение командной строки без GUI может быть разумно спроектировано для использования относительных путей. Предостережение заключается в том, что пользователю необходимо понять концепцию «текущего каталога», и программисту необходимо понять, как это сопоставляется с поведением библиотек Java IO. –
@ Стефен: Конечно, это возможно, вам придется только смириться с относительными путями, но это не рекомендуется. Преимущество метода classpath делает его более надежным. – BalusC
это зависит от того, что делает приложение. Например, если он управляет файлами, предоставленными пользователем, то подход classpath не имеет смысла. –
Предполагая, что пользователь не указал путь к файлу и введите что-то вроде «myfilenameonly». File file = new File(".", args[0])
необходимо в этом случае до найти файл (с учетом первого переданного аргумента).
Все платформы: File.getParent()
не возвращает родительский каталог, он должен вернуть «..» или имя родительского каталога в файловой системе определенным образом.
При создании файла «myfilenameonly» без указания полного пути к каталогу, в котором он находится, то File.getParent()
, например, возвратит нуль.
Смотрите далее: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=1228537
У меня была аналогичная проблема, я поместил мои файлы в папку с именем cobolcopybooks в папке Src и пытался получить доступ к ним в моем проекте, используя ClassLoader.getResource ("cobolcopybooks/demostud. cob ") , но я получал исключение из null-указателя, я несколько раз пытался его очистить и построить рабочие пространства после нескольких неудачных попыток. Я понял, что я не обновлял проект, чтобы файлы могли быть созданы вместе с проектом. i.e эти файлы должны быть видны вместе с другими файлами классов, так как во время выполнения корневой каталог будет bin-каталогом и он ищет там те файлы.
Другой вариант - просто выяснить, в какой директории указывается «текущий путь» в вашей среде - что бы это ни было. Как только вы выясните, вы можете выбрать свое решение оттуда. Возможно, это должен использовать соответствующий относительный путь к местоположению вашего файла или перемещение файла.
File testFile = new File("");
String currentPath = testFile.getAbsolutePath();
System.out.println("current path is: " + currentPath);
Это не идеально подходит для доставки кода, но он определенно полезен в качестве кода отладки, чтобы увидеть, что думает ваше приложение. – Steve
, не видя ваш код, мы не можем рассказать вам, что может происходить –