programing

Java JAR 파일에서 리소스에 대한 경로를 가져오는 방법

prostudy 2022. 5. 22. 11:23
반응형

Java JAR 파일에서 리소스에 대한 경로를 가져오는 방법

나는 자원으로 가는 길을 찾으려고 노력하고 있지만 운이 없었다.

IDE 및 JAR에서 모두 작동하지만 이렇게 하면 파일 내용만 얻을 수 있음:

ClassLoader classLoader = getClass().getClassLoader();
PrintInputStream(classLoader.getResourceAsStream("config/netclient.p"));

이렇게 하면:

ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("config/netclient.p").getFile());

결과는 다음과 같다.java.io.FileNotFoundException: file:/path/to/jarfile/bot.jar!/config/netclient.p (No such file or directory)

리소스 파일의 경로를 얻을 수 있는 방법이 있는가?

이건 고의야."파일"의 내용은 파일로 사용할 수 없을 수 있다.JAR 파일 또는 다른 종류의 리소스의 일부일 수 있는 클래스 및 리소스를 처리하고 있음을 기억하십시오.classloader는 자원에 파일 핸들을 제공할 필요가 없다. 예를 들어 jar 파일이 파일 시스템의 개별 파일로 확장되지 않았을 수 있다.

java.io을 얻어서 당신이 할 수 있는 모든 것.java.io이라면 스트림을 임시 파일로 복사하여 같은 작업을 할 수 있다.파일은 절대적으로 필요하다.

리소스를 로드할 때 다음 사항 간의 차이점을 확인하십시오.

getClass().getClassLoader().getResource("com/myorg/foo.jpg") //relative path

그리고

getClass().getResource("/com/myorg/foo.jpg")); //note the slash at the beginning

내 생각에, 이 혼란은 자원을 적재할 때 대부분의 문제를 야기하고 있는 것 같아.


또한 이미지를 로드할 때 보다 쉽게 사용할 수 있음getResourceAsStream():

BufferedImage image = ImageIO.read(getClass().getResourceAsStream("/com/myorg/foo.jpg"));

JAR 아카이브에서 (이미지가 아닌) 파일을 로드해야 하는 경우 다음을 시도해 보십시오.

File file = null;
String resource = "/com/myorg/foo.xml";
URL res = getClass().getResource(resource);
if (res.getProtocol().equals("jar")) {
    try {
        InputStream input = getClass().getResourceAsStream(resource);
        file = File.createTempFile("tempfile", ".tmp");
        OutputStream out = new FileOutputStream(file);
        int read;
        byte[] bytes = new byte[1024];

        while ((read = input.read(bytes)) != -1) {
            out.write(bytes, 0, read);
        }
        out.close();
        file.deleteOnExit();
    } catch (IOException ex) {
        Exceptions.printStackTrace(ex);
    }
} else {
    //this will probably work in your IDE, but not from a JAR
    file = new File(res.getFile());
}

if (file != null && !file.exists()) {
    throw new RuntimeException("Error: File " + file + " not found!");
}

한 줄의 대답은 -이다.

String path = this.getClass().getClassLoader().getResource(<resourceFileName>).toExternalForm()

기본적으로 방법은 URL을 제공한다. 이 URL에서 호출하여 경로를 추출할 수 있다.

나는 이 문제를 해결하는데 시간을 보냈다. 왜냐하면 어떤 해결책도 효과가 없었기 때문이다, 이상하게도!작업 디렉토리는 특히 Windows 아래의 시작 메뉴에서 JAR(또는 해당 프로그램의 경우)을 실행하는 경우 JAR의 디렉토리가 아닌 경우가 많다.그래서 내가 한 일이 있는데, JAR에서 실행되는 것과 마찬가지로 JAR 외부에서 실행되는 .class 파일에도 해당된다. (Windows 7에서 테스트했을 뿐이다.)

try {
    //Attempt to get the path of the actual JAR file, because the working directory is frequently not where the file is.
    //Example: file:/D:/all/Java/TitanWaterworks/TitanWaterworks-en.jar!/TitanWaterworks.class
    //Another example: /D:/all/Java/TitanWaterworks/TitanWaterworks.class
    PROGRAM_DIRECTORY = getClass().getClassLoader().getResource("TitanWaterworks.class").getPath(); // Gets the path of the class or jar.

    //Find the last ! and cut it off at that location. If this isn't being run from a jar, there is no !, so it'll cause an exception, which is fine.
    try {
        PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(0, PROGRAM_DIRECTORY.lastIndexOf('!'));
    } catch (Exception e) { }

    //Find the last / and cut it off at that location.
    PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(0, PROGRAM_DIRECTORY.lastIndexOf('/') + 1);
    //If it starts with /, cut it off.
    if (PROGRAM_DIRECTORY.startsWith("/")) PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(1, PROGRAM_DIRECTORY.length());
    //If it starts with file:/, cut that off, too.
    if (PROGRAM_DIRECTORY.startsWith("file:/")) PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(6, PROGRAM_DIRECTORY.length());
} catch (Exception e) {
    PROGRAM_DIRECTORY = ""; //Current working directory instead.
}

만일netclient.pJAR 파일 안에 있는데 다른 파일 안에 위치하기 때문에 경로가 없을 겁니다.그 경우에, 당신이 가질 수 있는 가장 좋은 길은 정말이다.file:/path/to/jarfile/bot.jar!/config/netclient.p.

이것은 항아리 자원의 불완전한 임시 파일 내용 복사를 방지하고 고유한 임시 파일 이름을 가지기 위해 스트림 플러시 및 닫힌 사용자 Tombart의 코드와 같다.

File file = null;
String resource = "/view/Trial_main.html" ;
URL res = getClass().getResource(resource);
if (res.toString().startsWith("jar:")) {
    try {
        InputStream input = getClass().getResourceAsStream(resource);
        file = File.createTempFile(new Date().getTime()+"", ".html");
        OutputStream out = new FileOutputStream(file);
        int read;
        byte[] bytes = new byte[1024];

        while ((read = input.read(bytes)) != -1) {
            out.write(bytes, 0, read);
        }
        out.flush();
        out.close();
        input.close();
        file.deleteOnExit();
    } catch (IOException ex) {
        ex.printStackTrace();
    }
} else {
    //this will probably work in your IDE, but not from a JAR
    file = new File(res.getFile());
}
         

항아리 파일 안의 경로를 이해해야 한다.
단순히 상대적인 것을 참고하라.그래서 만약 당신이 (내 파일)을 가지고 있다면.txt), 아래 foo.jar에 위치\src\main\resources디렉토리(메이븐 스타일).다음과 같이 언급할 수 있다.

src/main/resources/myfile.txt

만약 당신이 당신의 항아리를 버리면jar -tvf myjar.jarjar 파일 내에 출력 및 상대 경로가 표시되며, FORWARD SLASH를 사용한다.

나의 경우 Path 대신 URL 객체를 사용해 왔다.

파일

File file = new File("my_path");
URL url = file.toURI().toURL();

classloader를 사용하는 classpath의 리소스

URL url = MyClass.class.getClassLoader().getResource("resource_name")

내용을 읽어야 할 때 다음 코드를 사용할 수 있다.

InputStream stream = url.openStream();

그리고 InputStream을 사용하여 컨텐츠에 액세스할 수 있다.

A File은 파일 시스템의 파일을 추상화하는 것으로, 파일 시스템은 JAR의 내용이 무엇인지 전혀 알지 못한다.

URI를 사용해 보십시오. 자줏대감에서 유용할 수 있는 jar:/

규칙을 따르라!

/src/main/main/file

streamToFile(getClass().getClassLoader().getResourceAsStream("file"))

public static File streamToFile(InputStream in) {
    if (in == null) {
        return null;
    }

    try {
        File f = File.createTempFile(String.valueOf(in.hashCode()), ".tmp");
        f.deleteOnExit();

        FileOutputStream out = new FileOutputStream(f);
        byte[] buffer = new byte[1024];

        int bytesRead;
        while ((bytesRead = in.read(buffer)) != -1) {
            out.write(buffer, 0, bytesRead);
        }

        return f;
    } catch (IOException e) {
        LOGGER.error(e.getMessage(), e);
        return null;
    }
}

다음과 같은 길이 내게 통했다.classpath:/path/to/resource/in/jar

private static final String FILE_LOCATION = "com/input/file/somefile.txt";

//Method Body


InputStream invalidCharacterInputStream = URLClassLoader.getSystemResourceAsStream(FILE_LOCATION);

이것으로부터 얻는 것이 가장 좋은 선택이다.파일이나 URL이 아닌 입력 스트림을 가져오면 JAR 파일에서 독립 실행형으로 작동한다.

시간이 좀 늦을 수도 있지만 내 라이브러리 KResourceLoader를 사용하여 항아리로부터 리소스를 가져오십시오.

File resource = getResource("file.txt")

jar의 resource 폴더(java/main/resource) 안에 파일을 추가(imports.xml이라는 xml 파일을 추가한 것으로 가정함)한 후 주입ResourceLoader봄을 맹렬히 사용한다면.

@Autowired
private ResourceLoader resourceLoader;

inside tour function은 파일을 로드하기 위해 bellow 코드를 쓴다.

    Resource resource = resourceLoader.getResource("classpath:imports.xml");
    try{
        File file;
        file = resource.getFile();//will load the file
...
    }catch(IOException e){e.printStackTrace();}

아마도 이 방법은 빠른 해결책을 위해 사용될 수 있을 것이다.

public class TestUtility
{ 
    public static File getInternalResource(String relativePath)
    {
        File resourceFile = null;
        URL location = TestUtility.class.getProtectionDomain().getCodeSource().getLocation();
        String codeLocation = location.toString();
        try{
            if (codeLocation.endsWith(".jar"){
                //Call from jar
                Path path = Paths.get(location.toURI()).resolve("../classes/" + relativePath).normalize();
                resourceFile = path.toFile();
            }else{
                //Call from IDE
                resourceFile = new File(TestUtility.class.getClassLoader().getResource(relativePath).getPath());
            }
        }catch(URISyntaxException ex){
            ex.printStackTrace();
        }
        return resourceFile;
    }
}

에 있을 때jar파일, 리소스는 파일 시스템 계층이 아닌 패키지 계층에 절대적으로 위치함.그래서 만약 당신이 수업이 있다면com.example.Sweet이름이 지정된 리소스 로드./default.conf그러면 리소스의 이름이 다음과 같이 지정됨/com/example/default.conf.

하지만 항아리에 들어있다면 그건 파일이 아니야...

이 클래스 기능은 .jar 파일의 상대 파일 경로로 절대 파일 경로를 가져올 수 있다.


public class Utility {

    public static void main(String[] args) throws Exception {
        Utility utility = new Utility();
        String absolutePath = utility.getAbsolutePath("./absolute/path/to/file");
    }

    public String getAbsolutePath(String relativeFilePath) throws IOException {
        URL url = this.getClass().getResource(relativeFilePath);
        return url.getPath();
    }
}

대상 파일이 와 동일한 디렉토리인 경우Utility.java, 당신의 입력은./file.txt.

입력만 하는 경우/에서 getAbsolutePath()를 한다./Users/user/PROJECT_NAME/target/classes/. 이것은 당신이 이렇게 파일을 선택할 수 있다는 것을 의미함/com/example/file.txt.

참조URL: https://stackoverflow.com/questions/941754/how-to-get-a-path-to-a-resource-in-a-java-jar-file

반응형