Я пытался загрузить файл в webapp, и я получал исключение FileNotFound
, когда использовал FileInputStream
. Однако, используя тот же путь, мне удалось загрузить файл, когда я сделал getResourceAsStream()
.
В чем разница между двумя методами и почему одна работает, а другая - нет?
GetResourceAsStream() vs FileInputStream
Ответ 1
java.io.File
и выполняет действия в локальной файловой системе на диске. Коренной причиной вашей проблемы является то, что относительные пути в java.io
зависят от текущего рабочего каталога. То есть каталог, из которого запускается JVM (в вашем случае: веб-сервер). Это может быть, например, C:\Tomcat\bin
или что-то совершенно другое, но, таким образом, не C:\Tomcat\webapps\contextname
или что бы вы ни ожидали. В обычном проекте Eclipse это будет C:\Eclipse\workspace\projectname
. Вы можете узнать о текущем рабочем каталоге следующим образом:
System.out.println(new File(".").getAbsolutePath());
Однако рабочий каталог никоим образом не управляется программным способом. Вы действительно должны использовать абсолютные пути в API File
вместо относительных путей. Например. C:\full\path\to\file.ext
.
Вы не хотите жестко кодировать или угадывать абсолютный путь в Java (веб-приложениях). Это проблема только переносимости (т.е. Она работает в системе X, но не в системе Y). Обычная практика заключается в размещении этих ресурсов в классе classpath или добавлении его полного пути к пути к классам (в среде IDE, такой как Eclipse, которая находится в папке src
и в "пути сборки" соответственно), Таким образом, вы можете захватить их с помощью ClassLoader
ClassLoader#getResource()
или ClassLoader#getResourceAsStream()
. Он может находить файлы по отношению к "корню" пути к классам, поскольку вы по совпадению выяснили. В web-приложениях (или любом другом приложении, использующем несколько загрузчиков классов) рекомендуется использовать ClassLoader
, как было указано Thread.currentThread().getContextClassLoader()
для этого, чтобы вы могли также посмотреть "вне" контекста webapp.
Другой альтернативой в webapps является ServletContext#getResource()
и ее копия ServletContext#getResourceAsStream()
. Он имеет доступ к файлам, находящимся в общедоступной папке web
проекта webapp, включая папку /WEB-INF
. ServletContext
доступен в сервлетах с помощью унаследованного метода getServletContext()
, вы можете назвать его как-есть.
См. также:
- Где разместить и как читать файлы ресурсов конфигурации в сервлет-приложении?
- Что означает servletcontext.getRealPath( "/" ) и когда следует использовать его
- Рекомендуемый способ сохранения загруженных файлов в приложении сервлета
- Как временно сохранить сгенерированный файл в веб-приложении на основе сервлетов
Ответ 2
getResourceAsStream
- это правильный способ сделать это для веб-приложений (как вы уже узнали).
Причина в том, что чтение из файловой системы не может работать, если вы упаковываете свое веб-приложение в WAR. Это правильный способ упаковки веб-приложения. Он переносится таким образом, потому что вы не зависите от абсолютного пути к файлу или местоположения, где установлен ваш сервер приложений.
Ответ 3
FileInputStream загрузит путь к файлу, который вы передадите конструктору, как относительный из рабочего каталога процесса Java. Обычно в веб-контейнере это что-то вроде папки bin
.
getResourceAsStream()
будет загружать относительный путь к файлу из вашего пути к классу приложений.
Ответ 4
Класс FileInputStream
работает непосредственно с базовой файловой системой. Если файл, о котором идет речь, физически не присутствует там, он не сможет его открыть. Метод getResourceAsStream()
работает по-разному. Он пытается найти и загрузить ресурс с помощью ClassLoader
класса, на который он вызван. Это позволяет найти, например, ресурсы, встроенные в файлы jar
.
Ответ 5
classname.getResourceAsStream() загружает файл через загрузчик классов класса. Если класс появился из файла jar, то именно там будет загружен ресурс.
FileInputStream используется для чтения файла из файловой системы.
Ответ 6
Я здесь, разделяя оба использования, помечая их как "Чтение файла" (java.io) и "Чтение ресурса" (ClassLoader.getResourceAsStream()).
Чтение файлов - 1. Работает в локальной файловой системе. 2. Пытается найти файл, запрошенный из текущей запущенной директории JVM, как root 3. Идеально подходит для использования файлов для обработки в заранее определенном месте, например, /dev/files или C:\Data.
Чтение ресурса - 1. Работает на пути к классу 2. Пытается найти файл/ресурс в текущем или родительском пути к загрузчику классов. 3. Идеально подходит для загрузки файлов из упакованных файлов, таких как war или jar.