파일을 InputStream으로로드하는 다른 방법


216

차이점은 무엇입니까?

InputStream is = this.getClass().getClassLoader().getResourceAsStream(fileName)

InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)

InputStream is = this.getClass().getResourceAsStream(fileName)

각각 다른 것보다 사용하기에 더 적합한시기는 언제입니까?

읽으려는 파일이 파일을 읽는 클래스로 클래스 경로에 있습니다. 내 클래스와 파일은 동일한 jar에 있고 EAR 파일로 패키지되어 WebSphere 6.1에 배치됩니다.

답변:


289

fileName당신이 통과 하는 방법에 대한 미묘한 차이점이 있습니다 . 기본적으로, 당신은 2 개 가지 방법이 있습니다 ClassLoader.getResourceAsStream()Class.getResourceAsStream(). 이 두 가지 방법은 리소스를 다르게 찾습니다.

에서 Class.getResourceAsStream(path), 경로는 당신이에서 호출하는 클래스의 패키지 로컬 경로로 해석됩니다. 예를 들어, 호출 String.getResourceAsStream("myfile.txt")은 다음 위치에서 클래스 경로에서 파일을 찾습니다 "java/lang/myfile.txt". 경로가로 시작 /하면 절대 경로로 간주되며 클래스 경로의 루트에서 검색을 시작합니다. 따라서 전화 String.getResourceAsStream("/myfile.txt")는 수업 경로에서 다음 위치를 봅니다 ./myfile.txt.

ClassLoader.getResourceAsStream(path)모든 경로를 절대 경로로 간주합니다. 그래서 호출 String.getClassLoader().getResourceAsStream("myfile.txt")String.getClassLoader().getResourceAsStream("/myfile.txt")것이다 다음 위치에서 클래스 경로에있는 파일 모두보기 : ./myfile.txt.

이 게시물에서 위치를 언급 할 때마다 리소스를로드하는 Class 및 / 또는 ClassLoader에 따라 파일 시스템 자체 또는 해당 jar 파일 내의 위치 일 수 있습니다.

귀하의 경우 Application Server에서 클래스를로드하므로 Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)대신 대신 사용해야 합니다 this.getClass().getClassLoader().getResourceAsStream(fileName). this.getClass().getResourceAsStream()작동합니다.

특정 문제에 대한 자세한 정보는 이 기사 를 읽으십시오 .


Tomcat 7 이하 사용자에게 경고

이 질문에 대한 답변 중 하나는 Tomcat 7에 대한 설명이 올바르지 않은 것 같습니다. 나는 왜 그런지 알기 위해 주위를 둘러 보았습니다.

그래서 Tomcat의 WebAppClassLoader여러 버전에 대한 Tomcat의 소스 코드를 살펴 보았습니다 . findResource(String name)Tomcat 6과 Tomcat 7에서는 구현이 요청 된 자원에 대한 URL을 생성하는 데 가장 큰 책임이 있습니다. 그러나 Tomcat 8에서는 다릅니다.

버전 6 및 7에서는 구현시 자원 이름을 정규화하지 않습니다. 즉,이 버전에서는 Javadoc이 지정하는 것이므로 이벤트 classLoader.getResourceAsStream("/resource.txt")와 동일한 결과를 생성하지 못할 수도 있습니다 classLoader.getResourceAsStream("resource.txt"). [소스 코드]

그러나 버전 8에서는 자원 이름의 절대 버전이 사용되는 것을 보장하기 위해 자원 이름이 정규화됩니다. 따라서 Tomcat 8에서 위에서 설명한 두 호출은 항상 동일한 결과를 반환해야합니다. [소스 코드]

따라서 Tomcat 8 이전 버전을 사용 ClassLoader.getResourceAsStream()하거나 사용할 때는 각별히주의 Class.getResourceAsStream()해야합니다. 또한 class.getResourceAsStream("/resource.txt")실제로 전화를 걸면됩니다 classLoader.getResourceAsStream("resource.txt")(리딩 /은 제거됨).


2
나는 그것 getClass().getResourceAsStream("/myfile.txt")과 다르게 행동 한다고 확신합니다 getClassLoader().getResourceAsStream("/myfile.txt").
Brian Gordon

@ 브라이언 고든 : 그들은 다르게 행동하지 않습니다. 실제로, Class.getResourceAsStream (String)에 대한 javadoc은 "이 메소드는이 객체의 클래스 로더에 위임됩니다."라고 말한 다음,이 메소드를 위임하기 전에 상대 경로를 절대 경로로 변환하는 방법에 대한 많은 규칙을 제공합니다. 클래스 로더.
LordOfThePigs

@LordOfThePigs 실제 소스를보십시오. Class.getResourceAsStream은 절대 경로를 제공하면 선행 슬래시를 제거합니다.
Brian Gordon

4
@BrianGordon : 클래스 슬래시로 시작하든 아니든 모든 경로를 절대 경로로 해석하기 때문에 ClassLoader.getResourceAsStream ()과 동일하게 동작합니다. 따라서 경로가 절대적인 한 두 방법 모두 동일하게 작동합니다. 경로가 상대적이면 동작이 다릅니다.
LordOfThePigs

찾을 수없는 수 getClassLoader()String, 그것은 실수 또는 확장이 필요하십니까?
AaA

21

MyClass.class.getClassLoader().getResourceAsStream(path)코드와 관련된 리소스를로드하는 데 사용 합니다. MyClass.class.getResourceAsStream(path)바로 가기로 사용 하고 클래스 패키지 내에 패키지 된 리소스에 사용하십시오 .

Thread.currentThread().getContextClassLoader().getResourceAsStream(path)호출 코드에 밀접하게 묶이지 않고 클라이언트 코드의 일부인 리소스를 얻는 데 사용 합니다. 스레드 컨텍스트 클래스 로더가 무엇을 가리킬 수 있으므로주의해야합니다.


6

평범한 Java 7의 평범한 Java는 다른 종속성이 없습니다.

내가 넣어 file.txtc:\temp\내가 넣어 c:\temp\클래스 패스에.

두 통화간에 차이가있는 경우는 한 가지뿐입니다.

class J {

 public static void main(String[] a) {
    // as "absolute"

    // ok   
    System.err.println(J.class.getResourceAsStream("/file.txt") != null); 

    // pop            
    System.err.println(J.class.getClassLoader().getResourceAsStream("/file.txt") != null); 

    // as relative

    // ok
    System.err.println(J.class.getResourceAsStream("./file.txt") != null); 

    // ok
    System.err.println(J.class.getClassLoader().getResourceAsStream("./file.txt") != null); 

    // no path

    // ok
    System.err.println(J.class.getResourceAsStream("file.txt") != null); 

   // ok
   System.err.println(J.class.getClassLoader().getResourceAsStream("file.txt") != null); 
  }
}

매우 감사합니다, 나를 위해 'J.class.getResourceAsStream ( "file.txt")'
abbasalim

3

이 질문에 대한 답변뿐만 아니라 여기에있는 모든 답변은 "/foo/bar.properties"와 같은 절대 URL을로드하는 것이 class.getResourceAsStream(String)and로 동일하게 처리되었음을 제안합니다 class.getClassLoader().getResourceAsStream(String). 적어도 Tomcat 구성 / 버전 (현재 7.0.40)에는 해당되지 않습니다.

MyClass.class.getResourceAsStream("/foo/bar.properties"); // works!  
MyClass.class.getClassLoader().getResourceAsStream("/foo/bar.properties"); // does NOT work!

죄송합니다, 나는 만족스러운 설명이 없지만 tomcat은 클래스 로더와 함께 더러운 트릭과 그의 검은 마술을하고 차이를 유발한다고 생각합니다. 나는 항상 class.getResourceAsStream(String)과거에 사용 했지만 아무런 문제가 없었습니다.

추신 : 나는 또한 이것을 여기에 게시했습니다 .


아마도 바람둥이가 사양을 존중하지 않기로 결정하고 전달 된 모든 경로 ClassLoader.getResourceAsStream()를 절대 경로로 취급하지 않습니까? 위의 일부 주석에서 언급했듯이 Class.getResourceAsStream실제로 getClassLoader (). getResourceAsStream을 호출하지만 선행 슬래시를 제거 하기 때문에 그럴듯 합니다.
LordOfThePigs

자바 SE의 소스 코드를 확인한 후, 내가 대답을 잡고 생각 : 모두 Class.getResourceAsStream()ClassLoader.getResourceAsStream()호출 결국 궁극적으로 ClassLoader.findResource()누구의 javadoc에 명시 적으로 언급 보호 된 그 기본 구현 비어 방법 만 인 "클래스 로더의 구현은 지정하려면이 메소드를 오버라이드 (override) 자원을 찾을 수 있습니다. " 이 특정 방법에 대한 Tomcat의 구현에 결함이있을 수 있습니다.
LordOfThePigs

또한의 구현과 비교 한 WebAppClassLoader.findResource(String name)에서 톰캣 7 의와 톰캣 (8) , 그리고 중요한 차이점이 있다는 것을 나타납니다. Tomcat 8은 리소스 이름을 /포함하지 않는 경우 선행을 추가하여 리소스 이름을 명시 적으로 표준화하여 모든 이름을 절대적으로 만듭니다. Tomcat 7은 그렇지 않습니다. Tomcat 7의 버그
인데요

나는 그것에 대한 단락을 대답에 추가했습니다.
LordOfThePigs

0

성공하지 않고 파일을로드하는 몇 가지 방법을 시도한 후 FileInputStream완벽하게 작동하는을 사용할 수 있음을 기억 했습니다.

InputStream is = new FileInputStream("file.txt");

파일을로 읽는 다른 방법으로 InputStream, 현재 실행중인 폴더에서 파일을 읽습니다.


파일이 아니라 자원입니다. 대답이 맞지 않습니다.
Lorne의 후작

1
@ EJP 나는이 SO 답변을 끝내고 파일과 리소스의 차이점을 모르고 파일을로드하는 방법을 검색했습니다. 다른 사람에게 도움이 될 수 있으므로 답변을 삭제하지 않겠습니다.
António Almeida

-3

그것은 작동합니다, 이것을 시도하십시오 :

InputStream in_s1 =   TopBrandData.class.getResourceAsStream("/assets/TopBrands.xml");
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.