programing

jar 내에서 리소스 파일 읽기

prostudy 2022. 7. 11. 21:12
반응형

jar 내에서 리소스 파일 읽기

다음과 같이 항아리 내의 리소스를 읽습니다.

File file;
file = new File(getClass().getResource("/file.txt").toURI());
BufferedReader reader = new BufferedReader(new FileReader(file));

//Read the file

Eclipse에서 실행할 때는 정상적으로 동작합니다만, 이것을 항아리로 내보낸 후 실행하면, IlgulateArgument가 있습니다.예외:

Exception in thread "Thread-2"
java.lang.IllegalArgumentException: URI is not hierarchical

왜 그랬는지 모르겠지만 몇 가지 테스트 결과, 만약 내가 변한다면

file = new File(getClass().getResource("/file.txt").toURI());

로.

file = new File(getClass().getResource("/folder/file.txt").toURI());

반대로 작용합니다(항아리에서는 작동하지만 일식은 작동하지 않습니다).

이클립스를 사용하고 있는데 파일이 있는 폴더가 클래스 폴더에 있습니다.

리소스를 파일로 지정하는 대신 getResourceAsStream을 통해 리소스의 InputStream을 반환하도록 ClassLoader에 요청하십시오.

try (InputStream in = getClass().getResourceAsStream("/file.txt");
    BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
    // Use resource
}

의 경우file.txt클래스 패스에서 리소스를 사용할 수 있습니다.그러면 이 접근법은 classpath의 유무에 관계없이 동일하게 동작합니다.file.txt리소스가 에 있습니다.classes/디렉토리 또는 내부jar.

URI is not hierarchicaljar 파일 내의 리소스에 대한 URI가 다음과 같이 되어 있기 때문에 발생합니다.file:/example.jar!/file.txt. 내의 엔트리를 읽을 수 없습니다.jar(a)zip파일)이 오래된 파일인 것처럼 보이게 됩니다.

이는 다음 질문에 대한 답변으로 잘 설명됩니다.

항아리 내의 파일에 액세스 하려면 , 다음의 2개의 옵션이 있습니다.

  • 패키지명과 일치하는 디렉토리 구조(.jar 파일의 압축을 푼 후에는 .class 파일과 같은 디렉토리에 있어야 함)에 파일을 배치하고, 를 사용하여 액세스 합니다.getClass().getResourceAsStream("file.txt")

  • 파일을 루트에 배치하고(.jar 파일의 압축을 푼 후에는 루트에 있어야 함) 다음 명령을 사용하여 액세스합니다.Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt")

jar를 플러그인으로 사용하는 경우 첫 번째 옵션이 작동하지 않을 수 있습니다.

이전에도 이 문제가 있어서 폴백으로 로딩했습니다.기본적으로 첫 번째 방법은 .jar 파일 내에서 작동하고 두 번째 방법은 이클립스 또는 기타 IDE 내에서 작동합니다.

public class MyClass {

    public static InputStream accessFile() {
        String resource = "my-file-located-in-resources.txt";

        // this is the path within the jar file
        InputStream input = MyClass.class.getResourceAsStream("/resources/" + resource);
        if (input == null) {
            // this is how we load file within editor (eg eclipse)
            input = MyClass.class.getClassLoader().getResourceAsStream(resource);
        }

        return input;
    }
}

지금까지(2017년 12월) IDE 내외에서 모두 기능하는 솔루션은 이것뿐입니다.

Path Matching Resource Pattern Resolver 사용

주의: 스프링 부트에서도 동작합니다.

이 예에서는 src/main/resources/my_folder에 있는 파일을 읽고 있습니다.

try {
    // Get all the files under this inner resource folder: my_folder
    String scannedPackage = "my_folder/*";
    PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver();
    Resource[] resources = scanner.getResources(scannedPackage);

    if (resources == null || resources.length == 0)
        log.warn("Warning: could not find any resources in this scanned package: " + scannedPackage);
    else {
        for (Resource resource : resources) {
            log.info(resource.getFilename());
            // Read the file content (I used BufferedReader, but there are other solutions for that):
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
            String line = null;
            while ((line = bufferedReader.readLine()) != null) {
                // ...
                // ...                      
            }
            bufferedReader.close();
        }
    }
} catch (Exception e) {
    throw new Exception("Failed to read the resources folder: " + e.getMessage(), e);
}

저 같은 경우에는 드디어 이렇게 해서

import java.lang.Thread;
import java.io.BufferedReader;
import java.io.InputStreamReader;

final BufferedReader in = new BufferedReader(new InputStreamReader(
      Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt"))
); // no initial slash in file.txt

문제는 특정 서드파티 라이브러리에서 입력 스트림 대신 파일 경로 이름이 요구된다는 것입니다.대부분의 답변은 이 문제를 다루지 않습니다.

이 경우 한 가지 해결 방법은 리소스 내용을 임시 파일에 복사하는 것입니다."da" "jUnit"을 합니다.TemporaryFolder.

    private List<String> decomposePath(String path){
        List<String> reversed = Lists.newArrayList();
        File currFile = new File(path);
        while(currFile != null){
            reversed.add(currFile.getName());
            currFile = currFile.getParentFile();
        }
        return Lists.reverse(reversed);
    }

    private String writeResourceToFile(String resourceName) throws IOException {
        ClassLoader loader = getClass().getClassLoader();
        InputStream configStream = loader.getResourceAsStream(resourceName);
        List<String> pathComponents = decomposePath(resourceName);
        folder.newFolder(pathComponents.subList(0, pathComponents.size() - 1).toArray(new String[0]));
        File tmpFile = folder.newFile(resourceName);
        Files.copy(configStream, tmpFile.toPath(), REPLACE_EXISTING);
        return tmpFile.getAbsolutePath();
    }

올바른 구분 기호로 작업해야 합니다. 것을 했다./에서 " " "를 하여"를 사용합니다.File.separatorIDE에서는 정상적으로 동작했지만 빌드 JAR에서는 동작하지 않았습니다.

나는 해결책을 찾았다.

BufferedReader br = new BufferedReader(new InputStreamReader(Main.class.getResourceAsStream(path)));

"Main"을 코드화한 Java 클래스로 바꾸고 "path"를 jar 파일 내의 경로로 바꿉니다.

예를 들어 State1을 입력합니다.com.issac.state 패키지에 txt를 입력한 다음 Linux 또는 Mac을 실행하는 경우 경로를 "/com/issac/state/State1"로 입력합니다.Windows 를 실행하고 있는 경우는, 「\com\issac\state\State1」이라고 패스를 입력합니다.파일을 찾을 수 없음 예외가 발생하지 않는 한 .txt 확장자를 파일에 추가하지 마십시오.

이 코드는 Eclipse 및 Exported Runnable JAR에서 모두 작동합니다.

private String writeResourceToFile(String resourceName) throws IOException {
    File outFile = new File(certPath + File.separator + resourceName);

    if (outFile.isFile())
        return outFile.getAbsolutePath();
    
    InputStream resourceStream = null;
    
    // Java: In caso di JAR dentro il JAR applicativo 
    URLClassLoader urlClassLoader = (URLClassLoader)Cypher.class.getClassLoader();
    URL url = urlClassLoader.findResource(resourceName);
    if (url != null) {
        URLConnection conn = url.openConnection();
        if (conn != null) {
            resourceStream = conn.getInputStream();
        }
    }
    
    if (resourceStream != null) {
        Files.copy(resourceStream, outFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
        return outFile.getAbsolutePath();
    } else {
        System.out.println("Embedded Resource " + resourceName + " not found.");
    }
    
    return "";
}   

드디어 오류를 해결했습니다.

String input_path = "resources\\file.txt";
        
        input_path = input_path.replace("\\", "/");  // doesn't work with back slash
        
        URL file_url = getClass().getClassLoader().getResource(input_path);
        String file_path = new URI(file_url.toString().replace(" ","%20")).getSchemeSpecificPart();
        InputStream file_inputStream = file_url.openStream();

클래스 경로에서 ROOT 경로로 읽을 클래스 로더를 사용할 수 있습니다(처음에는 "/"가 없음).

InputStream in = getClass().getClassLoader().getResourceAsStream("file.txt"); 
BufferedReader reader = new BufferedReader(new InputStreamReader(in));

이유에선지.classLoader.getResource() 14에 했을 때 했습니다.WildFly 14에서 classLoader를 .getClass().getClassLoader() ★★★★★★★★★★★★★★★★★」Thread.currentThread().getContextClassLoader()manager가 됩니다.

getClass().getClassLoader()API를 사용합니다.

"클래스의 클래스 로더를 반환합니다.일부 구현에서는 부트스트랩클래스 로더를 나타내기 위해 null을 사용할 수 있습니다.이 메서드는 부트스트랩 클래스 로더에 의해 이 클래스가 로드된 경우 이러한 구현에서 null을 반환합니다."

WildFly를 사용하고 있는 경우 및 웹 어플리케이션을 사용해 보십시오.

request.getServletContext().getResource()【URL】【URL】ServletRequest를 사용하다

spring을 사용하는 경우 다음 방법을 사용하여 src/main/resources에서 파일을 읽을 수 있습니다.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.springframework.core.io.ClassPathResource;

  public String readFileToString(String path) throws IOException {

    StringBuilder resultBuilder = new StringBuilder("");
    ClassPathResource resource = new ClassPathResource(path);

    try (
        InputStream inputStream = resource.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {

      String line;

      while ((line = bufferedReader.readLine()) != null) {
        resultBuilder.append(line);
      }

    }

    return resultBuilder.toString();
  }

다음 코드는 스프링 부트(kotlin)로 동작합니다.

val authReader = InputStreamReader(javaClass.getResourceAsStream("/file1.json"))

파일로 읽고 싶다면, 비슷한 해결책이 아직 있다고 생각합니다.

    ClassLoader classLoader = getClass().getClassLoader();
    File file = new File(classLoader.getResource("file/test.xml").getFile());

언급URL : https://stackoverflow.com/questions/20389255/reading-a-resource-file-from-within-jar

반응형