code

Java에서 jar에서 파일을 읽는 방법은 무엇입니까?

codestyles 2020. 12. 28. 08:11
반응형

Java에서 jar에서 파일을 읽는 방법은 무엇입니까?


jar내 클래스 경로에 포함 된 s 중 하나에있는 XML 파일을 읽고 싶습니다 . 에 포함 된 파일을 어떻게 읽을 수 jar있습니까?


애플리케이션 내부에서 해당 파일을 읽으려면 다음을 사용하십시오.

InputStream input = getClass().getResourceAsStream("/classpath/to/my/file");

경로는 "/"로 시작하지만 파일 시스템의 경로가 아니라 클래스 경로에 있습니다. 따라서 파일이 클래스 경로 "org.xml"에 있고 이름이 myxml.xml 인 경우 경로는 "/org/xml/myxml.xml"과 같습니다.

InputStream은 파일의 내용을 읽습니다. 원하는 경우 리더로 포장 할 수 있습니다.

도움이 되었기를 바랍니다.


아, 제가 제일 좋아하는 과목 중 하나입니다. 기본적으로 클래스 경로를 통해 리소스를로드 할 수있는 두 가지 방법이 있습니다.

Class.getResourceAsStream(resource)

ClassLoader.getResourceAsStream(resource)

(유사한 방식으로 리소스의 URL을 가져온 다음 연결을 여는 다른 방법이 있지만 두 가지 직접적인 방법이 있습니다).

첫 번째 메서드는 리소스 이름을 변경 한 후 실제로 두 번째 메서드에 위임합니다. 본질적으로 리소스 이름에는 절대 (예 : "/ path / to / resource / resource")와 상대적 (예 : "resource")의 두 가지 종류가 있습니다. 절대 경로는 "/"로 시작합니다.

여기에 설명해야 할 예가 있습니다. com.example.A 클래스를 고려하십시오. 클래스 경로에서 하나는 / com / example / nested에 있고 다른 하나는 / top에있는 두 개의 자원을 고려하십시오. 다음 프로그램은 두 리소스에 액세스하는 9 가지 가능한 방법을 보여줍니다.

com.example 패키지;

공개 클래스 A {

    public static void main (String args []) {

        // Class.getResourceAsStream
        개체 리소스 = A.class.getResourceAsStream ( "nested");
        System.out.println ( "1 : A.class nested ="+ resource);

        리소스 = A.class.getResourceAsStream ( "/ com / example / nested");
        System.out.println ( "2 : A.class / com / example / nested ="+ 리소스);

        리소스 = A.class.getResourceAsStream ( "top");
        System.out.println ( "3 : A.class top ="+ 리소스);

        리소스 = A.class.getResourceAsStream ( "/ top");
        System.out.println ( "4 : A.class / top ="+ 리소스);

        // ClassLoader.getResourceAsStream
        ClassLoader cl = A.class.getClassLoader ();
        리소스 = cl.getResourceAsStream ( "nested");        
        System.out.println ( "5 : cl nested ="+ 리소스);

        리소스 = cl.getResourceAsStream ( "/ com / example / nested");
        System.out.println ( "6 : cl / com / example / nested ="+ 리소스);
        리소스 = cl.getResourceAsStream ( "com / example / nested");
        System.out.println ( "7 : cl com / example / nested ="+ resource);

        리소스 = cl.getResourceAsStream ( "top");
        System.out.println ( "8 : cl top ="+ 리소스);

        리소스 = cl.getResourceAsStream ( "/ top");
        System.out.println ( "9 : cl / top ="+ 리소스);
    }

}

프로그램의 출력은 다음과 같습니다.

1 : A.class nested=java.io.BufferedInputStream@19821f
2 : A.class /com/example/nested=java.io.BufferedInputStream@addbf1
3 : A.class top = null
4 : A.class /top=java.io.BufferedInputStream@42e816
5 : cl nested = null
6 : cl / com / example / nested = null
7 : cl com/example/nested=java.io.BufferedInputStream@9304b1
8 : cl top=java.io.BufferedInputStream@190d11
9 : cl / top = null

대부분은 예상 한대로 작동합니다. 클래스 상대 해결이 클래스와 관련되어 있으므로 Case-3은 실패하므로 "top"은 "/ com / example / top"을 의미하지만 "/ top"은 그것이 말하는 것을 의미합니다.

클래스 로더 상대 해결이 클래스 로더와 관련되어 있기 때문에 케이스 -5가 실패합니다. 그러나 예기치 않게 Case-6도 실패합니다. "/ com / example / nested"가 제대로 해결 될 것으로 예상 할 수 있습니다. 클래스 로더를 통해 중첩 된 리소스에 액세스하려면 Case-7을 사용해야합니다. 즉, 중첩 된 경로는 클래스 로더의 루트에 상대적입니다. 마찬가지로 Case-9는 실패하지만 Case-8은 통과합니다.

기억하세요 : java.lang.Class의 경우 getResourceAsStream ()은 클래스 로더에 위임합니다.

     public InputStream getResourceAsStream (String name) {
        이름 = resolveName (이름);
        ClassLoader cl = getClassLoader0 ();
        if (cl == null) {
            // 시스템 클래스.
            return ClassLoader.getSystemResourceAsStream (name);
        }
        return cl.getResourceAsStream (name);
    }

따라서 중요한 것은 resolveName ()의 동작입니다.

마지막으로, 기본적으로 getResourceAsStream ()을 제어하는 ​​클래스를로드 한 클래스 로더의 동작이고 클래스 로더는 종종 사용자 정의 로더이므로 리소스로드 규칙은 훨씬 더 복잡 할 수 있습니다. 예를 들어 웹 응용 프로그램의 경우 웹 응용 프로그램 컨텍스트에서 WEB-INF / classes 또는 WEB-INF / lib에서로드하지만 격리 된 다른 웹 응용 프로그램에서는로드하지 않습니다. 또한 잘 동작하는 클래스 로더는 부모에게 위임되므로이 메커니즘을 사용하여 클래스 경로의 중복 된 리소스에 액세스 할 수 없습니다.


Check first your class loader.

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

if (classLoader == null) {
    classLoader = Class.class.getClassLoader();
}

classLoader.getResourceAsStream("xmlFileNameInJarFile.xml");

// xml file location at xxx.jar
// + folder
// + folder
// xmlFileNameInJarFile.xml

A JAR is basically a ZIP file so treat it as such. Below contains an example on how to extract one file from a WAR file (also treat it as a ZIP file) and outputs the string contents. For binary you'll need to modify the extraction process, but there are plenty of examples out there for that.

public static void main(String args[]) {
    String relativeFilePath = "style/someCSSFile.css";
    String zipFilePath = "/someDirectory/someWarFile.war";
    String contents = readZipFile(zipFilePath,relativeFilePath);
    System.out.println(contents);
}

public static String readZipFile(String zipFilePath, String relativeFilePath) {
    try {
        ZipFile zipFile = new ZipFile(zipFilePath);
        Enumeration<? extends ZipEntry> e = zipFile.entries();

        while (e.hasMoreElements()) {
            ZipEntry entry = (ZipEntry) e.nextElement();
            // if the entry is not directory and matches relative file then extract it
            if (!entry.isDirectory() && entry.getName().equals(relativeFilePath)) {
                BufferedInputStream bis = new BufferedInputStream(
                        zipFile.getInputStream(entry));
                // Read the file
                    // With Apache Commons I/O
                 String fileContentsStr = IOUtils.toString(bis, "UTF-8");

                    // With Guava
                //String fileContentsStr = new String(ByteStreams.toByteArray(bis),Charsets.UTF_8);
                // close the input stream.
                bis.close();
                return fileContentsStr;
            } else {
                continue;
            }
        }
    } catch (IOException e) {
        logger.error("IOError :" + e);
        e.printStackTrace();
    }
    return null;
}

In this example I'm using Apache Commons I/O and if you are using Maven here is the dependency:

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>

Just for completeness, there has recently been a question on the Jython mailinglist where one of the answers referred to this thread.

The question was how to call a Python script that is contained in a .jar file from within Jython, the suggested answer is as follows (with "InputStream" as explained in one of the answers above:

PythonInterpreter.execfile(InputStream)

ReferenceURL : https://stackoverflow.com/questions/3369794/how-to-read-a-file-from-jar-in-java

반응형