IT이야기

java.nio.파일클래스 경로 리소스의 경로

cyworld 2022. 6. 20. 21:48
반응형

java.nio.파일클래스 경로 리소스의 경로

classpath 리소스(예: 에서 얻을 수 있는 것)를 취득하기 위한 API가 있습니까?이상적으로는 fancy new를 사용하고 싶습니다.Path클래스 패스 리소스가 있는 API.

이거면 되겠네요.

return Path.of(ClassLoader.getSystemResource(resourceName).toURI());

네가 하고 싶은 일은 전화야Files.lines(...)classpath에서 온 리소스(아마도 항아리 내에서 온 리소스)에 대해 설명합니다.

Oracle이 언제가 될지 개념을 복잡하게 만든 이후부터Path는 입니다.Path만들지 않음으로써getResourcejar 파일에 있는 경우 사용 가능한 경로를 반환합니다.필요한 것은 다음과 같습니다.

Stream<String> stream = new BufferedReader(new InputStreamReader(ClassLoader.getSystemResourceAsStream("/filename.txt"))).lines();

가장 일반적인 솔루션은 다음과 같습니다.

interface IOConsumer<T> {
    void accept(T t) throws IOException;
}
public static void processRessource(URI uri, IOConsumer<Path> action) throws IOException{
    try {
        Path p=Paths.get(uri);
        action.accept(p);
    }
    catch(FileSystemNotFoundException ex) {
        try(FileSystem fs = FileSystems.newFileSystem(
                uri, Collections.<String,Object>emptyMap())) {
            Path p = fs.provider().getPath(uri);
            action.accept(p);
        }
    }
}

주요 장애물은 두 가지 가능성 중 하나를 처리하는 것입니다. 즉, 기존 파일 시스템을 사용하되 닫으면 안 됩니다(예:fileURI 또는 Java 9의 모듈 스토리지) 또는 파일 시스템을 직접 열고 안전하게 닫아야 합니다(zip/jar 파일 등).

따라서 위의 솔루션은 실제 액션을 캡슐화하여interface는 두 가지 케이스를 모두 처리하여 두 번째 케이스에서는 안전하게 종료하고 Java 7에서 Java 18로 동작합니다.새로운 파일 시스템을 열기 전에 이미 열려 있는 파일 시스템이 있는지 여부를 조사하기 때문에, 애플리케이션의 다른 컴포넌트가 같은 zip/jar 파일의 파일 시스템을 이미 열었을 경우에도 작동합니다.

위의 모든 Java 버전에서 사용할 수 있습니다. 예를 들어 패키지의 내용을 나열하는 데 사용할 수 있습니다.java.lang이 예에서는) 로서Paths는 다음과 같습니다.

processRessource(Object.class.getResource("Object.class").toURI(),new IOConsumer<Path>(){
    public void accept(Path path) throws IOException {
        try(DirectoryStream<Path> ds = Files.newDirectoryStream(path.getParent())) {
            for(Path p: ds)
                System.out.println(p);
        }
    }
});

Java 8 이상에서는 람다 표현식 또는 메서드 참조를 사용하여 실제 작업을 나타낼 수 있습니다.

processRessource(Object.class.getResource("Object.class").toURI(), path -> {
    try(Stream<Path> stream = Files.list(path.getParent())) {
        stream.forEach(System.out::println);
    }
});

같은 일을 할 수 있습니다.


Java 9의 모듈 시스템의 최종 릴리스에서는 위의 코드 예가 깨졌습니다.9~12의 Java 버전이 일관되지 않게 경로를 반환한다./java.base/java/lang/Object.class위해서Paths.get(Object.class.getResource("Object.class"))반면/modules/java.base/java/lang/Object.class이 문제는 누락된 부분을 보완하여 해결할 수 있습니다./modules/부모 패스가 존재하지 않는 것으로 보고되었을 경우:

processRessource(Object.class.getResource("Object.class").toURI(), path -> {
    Path p = path.getParent();
    if(!Files.exists(p))
        p = p.resolve("/modules").resolve(p.getRoot().relativize(p));
    try(Stream<Path> stream = Files.list(p)) {
        stream.forEach(System.out::println);
    }
});

그런 다음 모든 버전 및 저장 방법으로 다시 작동합니다.JDK 13부터는 이 회피책이 필요 없게 되었습니다.

내장된 Zip 파일 시스템 공급자의 도움을 받아 이 작업을 수행할 수 있습니다.단, 리소스 URI를 직접 전달한다.Paths.get대신 먼저 엔트리 이름을 지정하지 않고 jar URI의 zip 파일 시스템을 만든 다음 해당 파일 시스템의 엔트리를 참조해야 합니다.

static Path resourceToPath(URL resource)
throws IOException,
       URISyntaxException {

    Objects.requireNonNull(resource, "Resource URL cannot be null");
    URI uri = resource.toURI();

    String scheme = uri.getScheme();
    if (scheme.equals("file")) {
        return Paths.get(uri);
    }

    if (!scheme.equals("jar")) {
        throw new IllegalArgumentException("Cannot convert to Path: " + uri);
    }

    String s = uri.toString();
    int separator = s.indexOf("!/");
    String entryName = s.substring(separator + 2);
    URI fileURI = URI.create(s.substring(0, separator));

    FileSystem fs = FileSystems.newFileSystem(fileURI,
        Collections.<String, Object>emptyMap());
    return fs.getPath(entryName);
}

업데이트:

이 코드는 새로운 FileSystem 개체를 열지만 닫지는 않기 때문에 위의 코드에는 리소스 누수가 포함되어 있다는 것은 올바르게 지적되었습니다.가장 좋은 방법은 Holger의 답변과 마찬가지로 소비자 수준의 작업자 개체를 전달하는 것입니다.작업자가 나중에 사용하기 위해 Path 개체를 저장하지 않는 한, 작업자가 경로와 관련하여 필요한 모든 작업을 수행할 수 있을 때까지 ZipFS FileSystem을 연 다음 FileSystem을 닫습니다.

제가 을 써서 읽었습니다.Paths츠키노리소스를 저장한 클래스의 참조와 리소스 자체의 이름만 있으면 되므로 사용이 매우 편리합니다.

public static Path getResourcePath(Class<?> resourceClass, String resourceName) throws URISyntaxException {
    URL url = resourceClass.getResource(resourceName);
    return Paths.get(url.toURI());
}  

Java8에서 NIO를 사용하여 리소스 폴더에서 파일 읽기

public static String read(String fileName) {

        Path path;
        StringBuilder data = new StringBuilder();
        Stream<String> lines = null;
        try {
            path = Paths.get(Thread.currentThread().getContextClassLoader().getResource(fileName).toURI());
            lines = Files.lines(path);
        } catch (URISyntaxException | IOException e) {
            logger.error("Error in reading propertied file " + e);
            throw new RuntimeException(e);
        }

        lines.forEach(line -> data.append(line));
        lines.close();
        return data.toString();
    }

jar 파일 내의 리소스에서는 URI를 생성할 수 없습니다.temp 파일에 쓴 다음 사용할 수 있습니다(java8).

Path path = File.createTempFile("some", "address").toPath();
Files.copy(ClassLoader.getSystemResourceAsStream("/path/to/resource"), path, StandardCopyOption.REPLACE_EXISTING);

https://docs.oracle.com/javase/8/docs/technotes/guides/io/fsp/zipfilesystemprovider.html에서 설명한 바와 같이 파일 시스템을 정의하여 jar 파일에서 리소스를 읽어야 합니다.다음 코드를 사용하여 jar 파일에서 리소스를 읽었습니다.

Map<String, Object> env = new HashMap<>();
try (FileSystem fs = FileSystems.newFileSystem(uri, env)) {

        Path path = fs.getPath("/path/myResource");

        try (Stream<String> lines = Files.lines(path)) {
            ....
        }
    }

언급URL : https://stackoverflow.com/questions/15713119/java-nio-file-path-for-a-classpath-resource

반응형