Java не может найти файл при пробежке Eclipse

Когда я запускаю JAVA-приложение, которое должно читать из файла в Eclipse, я получаю a java.io.FileNotFoundException, даже при том, что файл находится в корректном каталоге. Я могу скомпилировать и запустить приложение из командной строки очень хорошо; проблема только происходит в Eclipse больше чем с одним проектом и приложением. Существуют ли настройки, которые я должен изменить в конфигурациях выполнения или путях сборки, чтобы заставить это находить файл правильно?

21
задан BalusC 8 May 2010 в 04:25
поделиться

3 ответа

Проблема, скорее всего, в том, что ваше приложение использует относительный путь. Как говорит @BalusC, относительные пути могут быть проблематичными. Но ИМО, он заходит слишком далеко, когда говорит «[вы] вы не должны никогда использовать относительные пути в материалах java.io» .

Когда приложение открывает файл, используя (например) конструктор FileInputStream (File) , относительные пути разрешаются относительно «текущего каталога» в процессе, описанном ниже в документации javadoc для File.getAbsolutePath () .

[...] В противном случае этот путь разрешается системно-зависимым способом. В системах UNIX относительный путь становится абсолютным путем сопоставления его с текущим каталогом пользователя. В системах Microsoft Windows относительный путь становится абсолютным путем сопоставления его с текущим каталогом диска, названного по имени пути, если таковой имеется; в противном случае он разрешается для текущего пользовательского каталога.

Итак, сразу мы видим, что понятие «текущий каталог» имеет разные нюансы на платформах Windows и UNIX. Вторая проблема заключается в том, что в чистой Java вы не можете окончательно определить текущий каталог и, конечно же, не можете изменить его для текущей JVM, используя чистую Java. (При запуске JVM системное свойство user.dir устанавливается в текущий каталог, но ничто не мешает приложению изменить свойство , поэтому вы не можете полностью полагаться на него. Кроме того, изменение " user.dir "изменяет только способ разрешения пустого пути, а не относительные пути в целом.)

Так что же вы должны с этим делать?

  • Один из вариантов - использовать абсолютные пути для ссылки на файлы. Это надежно (почти) во всех случаях, но использование абсолютных имен путей может быть проблематичным, если пользователь должен ввести имя пути, или , если вам нужно избегать жестко запрограммированных (или настроенных) абсолютных имен путей.

  • Второй вариант - использовать относительные пути к классам и размещать файлы относительно каталога установки приложения. Это работает, если это то, что вам нужно, но представляет проблему, если вам нужно передать файл какому-либо библиотечному методу. Это также не помогает, если вы пытаетесь найти настройки приложения пользователя. (В общем, размещение пользовательских настроек в каталоге установки является ошибкой ...)

  • Третий вариант - присвоить файлу имя относительно некоторого абсолютного каталога, полученного вами откуда-то еще; например новый файл (System.getProperty ("home.dir"), "foo / bar"); .

  • Последний вариант - использовать относительные пути и предполагать, что пользователь знает, что такое текущий каталог. Для многих приложений, которые пользователь запускает из командной строки, это правильное решение.

В частном случае Eclipse есть простое решение. Перейдите к «конфигурации запуска», которую вы используете для запуска приложения, откройте вкладку «Аргументы» и щелкните переключатель «Другое». Затем введите абсолютный путь в качестве рабочего каталога для запущенного приложения. Когда дочерняя JVM запускается, она будет иметь указанный рабочий каталог в качестве текущего каталога.

30
ответ дан 29 November 2019 в 20:03
поделиться

Когда вы создаете приложение Java по умолчанию в Eclipse, вы получаете следующую структуру каталогов:

./ ProjectName / - корневой каталог
./ProjectName/bin/ - выходной каталог, содержащий файлы .class
./ ProjectName / src / - исходный каталог, содержащий файлы .java

Если ваше приложение запрашивает "./data.txt "он будет искать его относительно корневого каталога. Это «рабочий каталог», который можно настроить на вкладке аргументов в соответствии с ответом Мартина выше.

Вы говорите, что это работает из командной строки? Вероятно, это связано с тем, что при запуске двоичного файла java вы находитесь внутри папок bin или src. Рабочий каталог в этом случае - это тот каталог, в котором сейчас находится командная строка. Если, например, вы войдете в каталог / src /, скажем javac * .java , а затем запустите файлы оттуда, он будет искать «./data.txt» в каталоге / src /. Если вы войдете в каталог / bin / и запустите оттуда приложение, оно будет искать файл относительно каталога / bin /.

7
ответ дан 29 November 2019 в 20:03
поделиться

Вы не должны никогда использовать относительные пути в материале java.io . Путь стал бы зависеть от текущего рабочего каталога, который зависит от того, как вы запустили приложение, и, следовательно, сам по себе не является одинаковым для всех сред. Это неконтролируемо изнутри приложения Java. Беда с переносимостью! Всегда используйте абсолютные пути. Таким образом, например, c: /path/to/file.ext или /path/to/file.ext (с ведущей косой чертой) для UNIX и консортов (или даже Windows, если буква диска не имеющий отношения).

Каждый раз, когда вы хотите отправить некоторые файлы вместе с вашим приложением, обычно помещают их также в путь к классам . Таким образом, вы можете просто использовать ClassLoader # getResource () , чтобы получить его местоположение. Он возвращает URL . Вы можете использовать URL # toURI () или URL # getPath () и передать его конструктору java.io.File , а затем использовать его как обычно способ.

В вашем проекте Eclipse папка src (где находится ваш исходный код Java) в основном является корнем пути к классам. Кроме того, он, конечно, также охватывает все другие проекты и (внешние) папки, которые находятся в Build Path проекта.

Предполагая, что вы поместили конкретный файл в корень пути к классам:

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");
// ...
2
ответ дан 29 November 2019 в 20:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: