Когда я запускаю приложение Java, которое следует читать из файла в Eclipse, я получаю java.io.FileNotFoundException
, хотя файл находится в правильном каталоге. Я могу легко скомпилировать и запустить приложение из командной строки; проблема возникает только в Eclipse, с несколькими проектами и приложениями. Есть ли параметр, который мне нужно изменить в конфигурациях запуска или построить пути, чтобы найти его правильно?
Java не может найти файл при работе через Eclipse
Ответ 1
Проблема, скорее всего, в том, что ваше приложение использует относительный путь. Как говорит @BalusC, относительные пути могут быть проблематичными. Но ИМО, он идет слишком далеко, когда говорит: "[y] ou должен никогда использовать относительные пути в 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, в качестве текущего каталога будет указан указанный рабочий каталог.
Ответ 2
Другим вариантом является просто выяснить, какой каталог указывает "текущий путь" в вашей среде - что бы это ни было. Как только вы выясните, вы можете выбрать свое решение оттуда. Возможно, это использовать соответствующий относительный путь к вашему местоположению файла или перемещение файла.
File testFile = new File("");
String currentPath = testFile.getAbsolutePath();
System.out.println("current path is: " + currentPath);
Ответ 3
Когда вы создаете Java-приложение по умолчанию в Eclipse, вы получаете эту структуру каталогов:
./ProjectName/ - корневой каталог
./ProjectName/bin/ - каталог вывода, содержащий файлы .class
./ProjectName/src/ - исходный каталог, содержащий .java файлы
Если ваше приложение запрашивает "./data.txt", он будет искать его по отношению к корневому каталогу. Это "рабочий каталог" и может быть настроен на вкладке "Параметры" в соответствии с ответом Мартина выше.
Вы говорите, что это работает из командной строки? Вероятно, это связано с тем, что вы работаете в папке bin или src при запуске java-двоичного файла. Рабочий каталог в этом случае - это тот каталог, в котором сейчас находится командная строка. Если, например, вы заходите в каталог /src/, скажем javac *.java
, затем запустите файлы там, он будет искать "./data.txt" в каталоге /src/. Если вы заходите в каталог/bin/и запускаете свое приложение оттуда, он будет искать файл относительно каталога/bin/.
Ответ 4
Вы должны никогда использовать относительные пути в материалах 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");
// ...
Ответ 5
У меня была аналогичная проблема, я поместил файлы в папку cobolcopybooks внутри папки src и попытался получить к ним доступ в моем проекте, используя classloader.getResource( "cobolcopybooks/demostud.cob" ) но я получал исключение из null-указателя, я несколько раз пытался его очистить и построить рабочие пространства после нескольких неудачных попыток, я понял, что я не обновлял проект, чтобы файлы могли создаваться вместе с проектом. i.e эти файлы должны быть видны вместе с другими файлами классов, так как во время выполнения корневой каталог будет bin-каталогом и он ищет там те файлы.
Ответ 6
Предполагая, что пользователь не вводит полный путь к файлу в файл
и введите что-то вроде "myfilenameonly".
File file = new File(".", args[0])
необходимо в этом случае
найдите файл (обращая внимание на первый переданный аргумент).
Все платформы: File.getParent()
не возвращает родительский каталог,
он должен возвращать ".." или имя родительского каталога в файловой системе
конкретным способом.
Если вы создадите файл "myfilenameonly" без указания полного пути
в каталог, где он находится, File.getParent()
, например,
вернет null.
Смотрите далее: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=1228537