Я пытался загрузить файл в веб-приложении, и я получал a FileNotFound
исключение, когда я использовал FileInputStream
. Однако с помощью того же пути, я смог загрузить файл, когда я сделал getResourceAsStream()
. Каково различие между этими двумя методами, и почему каждый работает, в то время как другой не делает?
java.io.File
и консорты действуют в файловой системе локального диска. Основная причина вашей проблемы в том, что относительные пути в java.io
зависят от текущего рабочего каталога. Т.е. каталог, из которого запускается JVM (в вашем случае: веб-сервер). Это может быть, например, C: \ Tomcat \ bin
или что-то совершенно другое, но, таким образом, не C: \ Tomcat \ webapps \ contextname
или что-то еще, что вы ожидаете быть.В обычном проекте Eclipse это будет C: \ Eclipse \ workspace \ projectname
. Вы можете узнать о текущем рабочем каталоге следующим образом:
System.out.println(new File(".").getAbsolutePath());
Однако рабочий каталог никоим образом не управляется программно. Вы действительно должны предпочесть использовать абсолютные пути в File
API вместо относительных путей. Например. C: \ полный \ путь \ к \ file.ext
.
Вы не хотите жестко кодировать или угадывать абсолютный путь в приложениях Java (веб). Это только проблема переносимости (т.е. он работает в системе X, но не в системе Y). Обычной практикой является размещение таких ресурсов в пути к классам или добавление их полного пути в путь к классам (в среде IDE, такой как Eclipse, это папка src
и «путь сборки " соответственно). Таким образом, вы можете получить их с помощью ClassLoader
с помощью ClassLoader # getResource ()
или ClassLoader # getResourceAsStream ()
. Как вы случайно поняли, он может располагать файлы относительно «корня» пути к классам. В веб-приложениях (или любых других приложениях, использующих несколько загрузчиков классов) рекомендуется использовать ClassLoader
, возвращенный Thread.currentThread (). GetContextClassLoader ()
для этого, чтобы вы могли смотреть "вовне". "контекст веб-приложения.
Другой альтернативой в веб-приложениях является ServletContext # getResource ()
и его аналог ServletContext # getResourceAsStream ()
.Он может получить доступ к файлам, расположенным в общедоступной папке web
проекта webapp, включая папку / WEB-INF
. ServletContext
доступен в сервлетах с помощью унаследованного метода getServletContext ()
, вы можете вызывать его как есть.
getResourceAsStream
- правильный способ сделать это для веб-приложений (как вы уже узнали).
Причина в том, что чтение из файловой системы не может работать, если вы упаковываете свое веб-приложение в WAR. Это правильный способ упаковки веб-приложения. Таким образом, он переносится, потому что вы не зависите от абсолютного пути к файлу или места, где установлен ваш сервер приложений.
FileInputStream загрузит путь к файлу вы переходите к конструктору как относительный из рабочего каталога процесса Java. Обычно в веб-контейнере это что-то вроде папки bin
.
getResourceAsStream ()
загрузит относительный путь к файлу из пути к классам вашего приложения .
Класс FileInputStream
работает напрямую с базовой файловой системой. Если рассматриваемого файла там физически нет, он не сможет его открыть. Метод getResourceAsStream ()
работает иначе. Он пытается найти и загрузить ресурс, используя ClassLoader
класса, для которого он вызван. Это позволяет ему находить, например, ресурсы, встроенные в файлы jar
.
classname.getResourceAsStream() загружает файл через загрузчик класса classname. Если класс пришел из jar-файла, то ресурс будет загружен именно оттуда.
FileInputStream используется для чтения файла из файловой системы.