2010-05-08 2 views
19

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

+1

, не видя ваш код, мы не можем рассказать вам, что может происходить –

ответ

28

Проблема заключается в том, что, скорее всего, ваше приложение использует относительный путь к файлу. Как говорит @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 запущен, он будет иметь указанный рабочий каталог в качестве его текущего каталога.

+0

Спасибо за помощь! – derekerdmann

+0

У меня возникла проблема с запуском моего приложения из eclipse, неспособным прочитать файл свойств, который был в корне моего проекта.После того, как я попытался настроить рабочий каталог в конфигурации запуска на $ {workspace_loc}/myproject/bin, он сработал !. – Krishnaraj

+0

@ Кришнарай - Вот что я сказал в последнем абзаце моего ответа :-) –

6

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

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

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

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

+0

Спасибо за помощь. Текстовые файлы, которые мне нужны, существуют в каталоге/bin /, поэтому это не проблема. Я буду играть с относительными путями и посмотреть, что я могу получить. – derekerdmann

2

Вы должны Никогда использовать относительные пути в 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"); 
// ... 
+0

приложение командной строки без GUI может быть разумно спроектировано для использования относительных путей. Предостережение заключается в том, что пользователю необходимо понять концепцию «текущего каталога», и программисту необходимо понять, как это сопоставляется с поведением библиотек Java IO. –

+0

@ Стефен: Конечно, это возможно, вам придется только смириться с относительными путями, но это не рекомендуется. Преимущество метода classpath делает его более надежным. – BalusC

+0

это зависит от того, что делает приложение. Например, если он управляет файлами, предоставленными пользователем, то подход classpath не имеет смысла. –

1

Предполагая, что пользователь не указал путь к файлу и введите что-то вроде «myfilenameonly». File file = new File(".", args[0]) необходимо в этом случае до найти файл (с учетом первого переданного аргумента).

Все платформы: File.getParent() не возвращает родительский каталог, он должен вернуть «..» или имя родительского каталога в файловой системе определенным образом.

При создании файла «myfilenameonly» без указания полного пути к каталогу, в котором он находится, то File.getParent(), например, возвратит нуль.

Смотрите далее: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=1228537

2

У меня была аналогичная проблема, я поместил мои файлы в папку с именем cobolcopybooks в папке Src и пытался получить доступ к ним в моем проекте, используя ClassLoader.getResource ("cobolcopybooks/demostud. cob ") , но я получал исключение из null-указателя, я несколько раз пытался его очистить и построить рабочие пространства после нескольких неудачных попыток. Я понял, что я не обновлял проект, чтобы файлы могли быть созданы вместе с проектом. i.e эти файлы должны быть видны вместе с другими файлами классов, так как во время выполнения корневой каталог будет bin-каталогом и он ищет там те файлы.

8

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

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

Это не идеально подходит для доставки кода, но он определенно полезен в качестве кода отладки, чтобы увидеть, что думает ваше приложение. – Steve