getResourceAsStream() против FileInputStream
Я пытался загрузить файл в веб-приложение, и я получаю FileNotFound
исключение, когда я использовал FileInputStream
, Однако, используя тот же путь, я смог загрузить файл, когда я сделал getResourceAsStream()
, В чем разница между этими двумя методами, и почему один работает, а другой нет?
6 ответов
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:\full\path\to\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()
метод, вы можете назвать его как есть.
Смотрите также:
- Где разместить и как прочитать файлы ресурсов конфигурации в приложении на основе сервлетов?
- Что означает servletcontext.getRealPath("/") и когда я должен его использовать
- Рекомендуемый способ сохранения загруженных файлов в приложении сервлета
- Как временно сохранить созданный файл в веб-приложении на основе сервлета
getResourceAsStream
это правильный способ сделать это для веб-приложений (как вы уже узнали).
Причина в том, что чтение из файловой системы не может работать, если вы упакуете свое веб-приложение в WAR. Это правильный способ упаковки веб-приложения. Это переносимо, потому что вы не зависите от абсолютного пути к файлу или местоположения, где установлен ваш сервер приложений.
FileInputStream загрузит путь к файлу, который вы передаете конструктору, относительно рабочего каталога процесса Java. Обычно в веб-контейнере это что-то вроде bin
папка.
getResourceAsStream()
загрузит путь к файлу относительно пути к классу вашего приложения.
FileInputStream
Класс работает напрямую с базовой файловой системой. Если рассматриваемый файл не присутствует там физически, он не сможет открыть его. getResourceAsStream()
Метод работает по-другому. Он пытается найти и загрузить ресурс, используя ClassLoader
класса это называется. Это позволяет ему находить, например, ресурсы, встроенные в jar
файлы.
classname.getResourceAsStream() загружает файл через загрузчик классов с именем класса. Если класс пришел из jar-файла, именно из него будет загружен ресурс.
FileInputStream используется для чтения файла из файловой системы.
Я здесь, разделяя оба использования, помечая их как "Чтение файла" (java.io) и "Чтение ресурса" (ClassLoader.getResourceAsStream()).
Чтение файла - 1. Работает в локальной файловой системе. 2. Пытается найти файл, запрошенный из текущей запущенной директории JVM, как root 3. Идеально подходит для использования файлов для обработки в заранее определенном месте, например,/dev/files или C: \ Data.
Resource Read -1. Работает с путем к классу 2. Пытается найти файл / ресурс в текущем или родительском пути к загрузчику классов. 3. Идеально подходит для загрузки файлов из упакованных файлов, таких как war или jar.