getResourceAsStream () 대 FileInputStream


173

webapp에 파일을로드하려고했지만을 FileNotFound사용할 때 예외 가 발생했습니다 FileInputStream. 그러나 동일한 경로를 사용하여 파일을로드 할 수있었습니다 getResourceAsStream(). 두 방법의 차이점은 무엇이며 다른 하나는 작동하지 않는 이유는 무엇입니까?

답변:


256

java.io.File및 배우자들은 로컬 디스크 파일 시스템에 작용한다. 문제의 근본 원인은 상대 경로 java.io가 현재 작업 디렉토리에 의존하기 때문입니다. 즉, JVM (웹 서버의 경우)이 시작된 디렉토리입니다. 예를 들어 이것은 C:\Tomcat\bin완전히 다르거 나 전혀 달라도되지만 예상치 못한 결과 일 C:\Tomcat\webapps\contextname 수도 있습니다. 일반적인 이클립스 프로젝트에서는 그렇습니다 C:\Eclipse\workspace\projectname. 다음과 같은 방법으로 현재 작업 디렉토리에 대해 배울 수 있습니다.

System.out.println(new File(".").getAbsolutePath());

그러나 작업 디렉토리는 프로그래밍 방식으로 제어 할 수 없습니다. 당신은 정말 사용을 선호한다 절대 에 경로를 File대신 상대 경로의 API. 예 :C:\full\path\to\file.ext .

Java (웹) 응용 프로그램의 절대 경로를 하드 코딩하거나 추측하고 싶지 않습니다. 이는 이식성 문제 일뿐입니다 (즉, 시스템 X에서는 실행되지만 시스템 Y에서는 실행되지 않음). 일반적인 방법은 이러한 종류의 리소스를 classpath 에 배치하거나 클래스 경로에 전체 경로를 추가하는 것입니다 (Eclipse와 같은 IDE에서 각각 src폴더 및 "빌드 경로"). 이 방법으로 ClassLoaderby ClassLoader#getResource()또는의 도움으로 그들을 잡을 수 있습니다 ClassLoader#getResourceAsStream(). 우연의 일치로 클래스 경로의 "루트"를 기준으로 파일을 찾을 수 있습니다. 웹 응용 프로그램 (또는 여러 클래스 로더를 사용하는 다른 응용 프로그램)에서는에서 ClassLoader반환 한대로 사용하는 것이 좋습니다Thread.currentThread().getContextClassLoader() 컨텍스트를 "외부"로 볼 수 있도록 대해 .

webapps의 또 다른 대안은 ServletContext#getResource()및 대응 ServletContext#getResourceAsStream()입니다. web폴더를 포함하여 webapp 프로젝트 의 공용 폴더에있는 파일에 액세스 할 수 있습니다 /WEB-INF. 은 ServletContext상속에 의해 서블릿에서 사용할 수 있습니다getServletContext() 방법, 당신은있는 그대로 호출 할 수 있습니다.

또한보십시오:



27

getResourceAsStream 이미 배운대로 웹 앱에 올바른 방법입니다.

웹 앱을 WAR로 패키지화하면 파일 시스템에서 읽을 수 없기 때문입니다. 이것은 웹앱을 패키징하는 올바른 방법입니다. 절대 파일 경로 또는 앱 서버가 설치된 위치에 의존하지 않기 때문에 이식성이 뛰어납니다.


3
+1- "작동 할 수 없음"이 너무 강합니다. (파일 시스템에서 읽기 작업을 수행 할 수 있지만 이식 가능하게하는 것은 까다 롭고 ... 특히 리소스가 JAR에있는 경우 훨씬 더 많은 코드입니다.)
Stephen C

1
멍청하고 아주 좋은 대답과 당신은 내 실수가 무엇인지 설명했지만 BalusC는 매우 자세하게 설명했습니다. 그의 대답은 내부 세부 사항도 알고 싶은 사람들에게 도움이 될 것이라고 생각합니다. 수락 된 답변을 그의 것으로 바꾸는 것을 신경 쓰지 않기를 바랍니다!
Vivin Paliath

@Stephen- "작동 할 수 없습니다"가 너무 강하다고 생각하지 않습니다. 앱 서버에 대한 경로가 다른 두 개의 서로 다른 서버에 배포하는 것만 큼 간단하더라도 서버가 손상됩니다. 요점은 WAR을 가능한 한 독립적으로 만들어야한다는 것입니다. 당신의 요점은 맞지만, 나는 내 말을 고수하려고합니다.
duffymo

14

FileInputStream은 작업 디렉토리 와 관련하여 생성자에 전달하는 파일 경로를로드합니다. Java 프로세스 를 . 일반적으로 웹 컨테이너에서는 bin폴더 와 유사 합니다.

getResourceAsStream()응용 프로그램의 classpath에서 상대적인 파일 경로를로드합니다 .


12

FileInputStream클래스는 기본 파일 시스템과 직접 작동합니다. 해당 파일이 실제로 존재하지 않으면 파일을 열 수 없습니다. 이 getResourceAsStream()방법은 다르게 작동합니다. ClassLoader호출 된 클래스를 사용하여 자원을 찾아로드하려고 시도합니다 . 예를 들어 jar파일에 포함 된 리소스를 찾을 수 있습니다.


jar 파일은 여전히 ​​파일 시스템에 물리적으로 "존재하고"다른 파일에 포함되어 있습니다.
matt b

1
물론입니다. 그러나 응용 프로그램이 jar파일 형식과 그 의미에 대해 알지 않는 한 일반적으로 파일 시스템에서 독립 엔티티로 간주되는 것은 아닙니다 . 그리고 Java에서는 적절한 ClassLoader지식이있을 수 있지만 일반 FileInputStream은 그렇지 않습니다.
Dirk

7

classname.getResourceAsStream ()은 classname의 클래스 로더를 통해 파일을로드합니다. 클래스가 jar 파일에서 온 경우 자원이로드 될 위치입니다.

FileInputStream은 파일 시스템에서 파일을 읽는 데 사용됩니다.


0

여기에서는 File Read (java.io) 및 Resource Read (ClassLoader.getResourceAsStream ())로 표시하여 사용법을 분리하여 여기에 있습니다.

파일 읽기-1 . 로컬 파일 시스템에서 작동합니다. 2. 현재 JVM 시작 디렉토리에서 요청한 파일을 루트로 찾으려고 시도합니다. / dev / files 또는 C : \ Data와 같이 미리 결정된 위치에서 처리하기 위해 파일을 사용할 때 이상적입니다.

리소스 읽기-1 . 클래스 경로 2에서 작동합니다. 현재 또는 상위 클래스 로더 클래스 경로에서 파일 / 자원을 찾으려고 시도합니다. 3. war 또는 jar와 같은 패키지 파일에서 파일을로드 할 때 이상적입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.