실행중인 JAR 파일의 경로를 얻는 방법?


580

내 코드는 foo.jar 와 같은 JAR 파일 내에서 실행되며 코드에서 foo.jar 실행 폴더가 무엇인지 알아야합니다 .

경우에 따라서, foo.jar에이C:\FOO\, 나는 상관없이 나의 현재 작업 디렉토리가 무엇인지 그 경로를 얻을 싶어요.


경로에 공백이 포함 된 경우 작동하는 솔루션에 대해서는 Fab의 답변을 참조하십시오. 또한 아래의 답변 중 일부는 제목 (jar 경로)으로 질문을 해결하고 일부는 질문 자체 (jar를 포함하는 폴더의 경로)를 해결하며 일부는 jar 파일 내부의 클래스에 대한 경로를 제공합니다.
Andy Thomas

32
ANT에서 사용할 때주의하십시오! ============== 문자열 경로를 호출합니다 = SomeClass.class.getProtectionDomain (). getCodeSource (). getLocation (). getPath (); 얻을 : /C:/apache-ant-1.7.1/lib/ant.jar 유용하지 않습니다!
Dino Fancellu

흥미 롭군 내가 사용한 원래 코드는 개미에서 실행되지 않았으므로 문제가되지 않습니다.
Thiago Chaves

2
@ 디노 Fancellu, 난 당신이 설명한 것을 정확히 경험했다. 개발 중에 작동하며 jar로 빌드하면 실패합니다.
Buddy

답변:


539
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
    .toURI()).getPath();

"MyClass"를 클래스 이름으로 바꾸십시오.

클래스가 파일이 아닌 위치에서로드 된 경우 분명히 이상한 일을합니다.


43
toURI()단계는 공백과 플러스를 포함한 특수 문자의 문제를 피하기 위해 필수적입니다. 올바른 한 줄짜리는 다음과 같습니다 . 많은 특수 문자에는 return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI()); 사용 URLDecoder이 작동하지 않습니다. 자세한 내용은 아래 답변을 참조하십시오.
ctrueden

4
참고 : 이것은 jar 파일의 이름을 포함하는 경로를 반환합니다
Buddy

8
이것이 실행중인 디렉토리 대신 jar 파일을 가리 키지 않습니까? 이 작업을 위해 getParentFile () 결과를 수행해야합니다.
FOO

1
또한 getProtectionDomainstracktrace에서 수업을받는 경우 null입니다.val strace = Thread.currentThread().getStackTrace; val path = strace(1).getClass.getProtectionDomain
bbarker

1
이 메소드를 최대 Java 8과 함께 사용 이 메소드를 외부 Jar에있는 클래스에 배치하고 클래스 경로를 통해로드하면 실제 실행중인 Jar 대신 외부 Jar의 경로가 제공됩니다.
Mr00Anderson

189

나를위한 최고의 솔루션 :

String path = Test.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = URLDecoder.decode(path, "UTF-8");

공백과 특수 문자의 문제를 해결해야합니다.


8
참고 사항 : Jar 에서이 함수를 호출하는 동안 jar의 이름이 끝에 추가되므로 다음을 실행해야했습니다. path.substring (0, path.lastIndexOf ( "/") + 1);
will824

11
/가 반드시 경로 구분 기호 인 것은 아닙니다. 대신 (new File (path)). getParentFile (). getPath ()를 수행해야합니다.
pjz

10
여기에 JAR 파일 이름에 문제가 없습니다. UTF 변환은 URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");Linux 에서 @Iviggiani one ( ) 과 함께 완벽한 솔루션으로 보입니다 . 그러나 Windows에서는 시도하지 않았습니다.
우분투 로이드

2
감사합니다. Linux 및 Windows에서 FileInputStream을 사용하여 JAR 외부의 파일을로드 할 수있었습니다. 파일 이름 앞에 해독 경로를 추가해야했습니다.
giorgio79

11
주의 : URLDecoder특수 문자를 해독하는 데 사용하지 않는 것이 좋습니다 . 특히, 같은 문자 +는 공백으로 잘못 디코딩됩니다. 자세한 내용은 내 답변을 참조하십시오.
ctrueden

153

File주어진에 대한를 얻으려면 Class두 단계가 있습니다.

  1. 변환 ClassA를URL
  2. 변환 URLA를File

두 단계를 이해하고 혼동하지 않는 것이 중요합니다.

일단 당신이 FilegetParentFile 있으면 필요한 경우 포함 폴더를 얻기 위해 전화 를 걸 수 있습니다 .

1 단계: ClassURL

다른 답변에서 논의 된 바와 같이, URL관련성을 찾는 두 가지 주요 방법 이 Class있습니다.

  1. URL url = Bar.class.getProtectionDomain().getCodeSource().getLocation();

  2. URL url = Bar.class.getResource(Bar.class.getSimpleName() + ".class");

둘 다 장단점이 있습니다.

getProtectionDomain접근 방식은 클래스의 기본 위치 (예 : 포함하는 JAR 파일)를 생성합니다. 그러나를 SecurityException호출 할 때 Java 런타임의 보안 정책이 getProtectionDomain()발생할 수 있으므로 응용 프로그램을 다양한 환경에서 실행해야하는 경우 모두 테스트하는 것이 가장 좋습니다.

getResource접근 방식은 클래스의 전체 URL 리소스 경로를 생성하므로 추가 문자열 조작을 수행해야합니다. 그것은있을 수 있습니다 file:경로뿐만 아니라 될 수 jar:file:또는 같은 천하고도 뭔가 bundleresource://346.fwk2106232034:4/foo/Bar.classOSGi 프레임 워크 내에서 실행하는 경우. 반대로,이 getProtectionDomain방법 file:은 OSGi 내에서도 URL을 올바르게 생성합니다 .

모두 참고 getResource("")하고 getResource(".")클래스가 JAR 파일 내에 거주 할 때, 내 테스트에서 실패; 두 호출 모두 null을 반환했습니다. 따라서 위의 # 2 호출이 더 안전 해 보이므로 대신 권장합니다.

2 단계 : URLFile

어느 쪽이든, 일단 URL다음 단계는로 변환됩니다 File. 이것은 그 자체의 도전이다. 참조 그것에 대해 Kohsuke 가와구치의 블로그 게시물을 전체 세부 사항은 있지만, 짧은에, 당신은 사용할 수 있습니다new File(url.toURI()) URL의 형식이 올바른 한 .

마지막 으로을 사용 하지 않는 것이 좋습니다URLDecoder . 의 URL의 일부 문자 :/특히는 유효한 URL 인코딩 된 문자 수 없습니다. 로부터 URLDecoder의 자바 독 :

인코딩 된 문자열의 모든 문자는 "a"~ "z", "A"~ "Z", "0"~ ​​"9"및 "-", "_", "중 하나 인 것으로 가정합니다. . "및"* ". "%"문자는 허용되지만 특수 이스케이프 된 시퀀스의 시작으로 해석됩니다.

...

이 디코더가 잘못된 문자열을 처리 할 수있는 두 가지 방법이 있습니다. 잘못된 문자를 그대로 두거나 IllegalArgumentException을 발생시킬 수 있습니다. 디코더가 취하는 접근법은 구현에 맡겨져 있습니다.

실제로, URLDecoder일반적으로 IllegalArgumentException위의 위협 으로 던져지지 않습니다 . 파일 경로에로 인코딩 된 공백 %20이 있으면이 방법이 작동하는 것처럼 보일 수 있습니다. 그러나 파일 경로에 영숫자가 아닌 다른 문자가 있으면 파일 경로를 조작하는 +데 문제가 있습니다 URLDecoder.

작업 코드

이러한 단계를 수행하기 위해 다음과 같은 방법이있을 수 있습니다.

/**
 * Gets the base location of the given class.
 * <p>
 * If the class is directly on the file system (e.g.,
 * "/path/to/my/package/MyClass.class") then it will return the base directory
 * (e.g., "file:/path/to").
 * </p>
 * <p>
 * If the class is within a JAR file (e.g.,
 * "/path/to/my-jar.jar!/my/package/MyClass.class") then it will return the
 * path to the JAR (e.g., "file:/path/to/my-jar.jar").
 * </p>
 *
 * @param c The class whose location is desired.
 * @see FileUtils#urlToFile(URL) to convert the result to a {@link File}.
 */
public static URL getLocation(final Class<?> c) {
    if (c == null) return null; // could not load the class

    // try the easy way first
    try {
        final URL codeSourceLocation =
            c.getProtectionDomain().getCodeSource().getLocation();
        if (codeSourceLocation != null) return codeSourceLocation;
    }
    catch (final SecurityException e) {
        // NB: Cannot access protection domain.
    }
    catch (final NullPointerException e) {
        // NB: Protection domain or code source is null.
    }

    // NB: The easy way failed, so we try the hard way. We ask for the class
    // itself as a resource, then strip the class's path from the URL string,
    // leaving the base path.

    // get the class's raw resource path
    final URL classResource = c.getResource(c.getSimpleName() + ".class");
    if (classResource == null) return null; // cannot find class resource

    final String url = classResource.toString();
    final String suffix = c.getCanonicalName().replace('.', '/') + ".class";
    if (!url.endsWith(suffix)) return null; // weird URL

    // strip the class's path from the URL string
    final String base = url.substring(0, url.length() - suffix.length());

    String path = base;

    // remove the "jar:" prefix and "!/" suffix, if present
    if (path.startsWith("jar:")) path = path.substring(4, path.length() - 2);

    try {
        return new URL(path);
    }
    catch (final MalformedURLException e) {
        e.printStackTrace();
        return null;
    }
} 

/**
 * Converts the given {@link URL} to its corresponding {@link File}.
 * <p>
 * This method is similar to calling {@code new File(url.toURI())} except that
 * it also handles "jar:file:" URLs, returning the path to the JAR file.
 * </p>
 * 
 * @param url The URL to convert.
 * @return A file path suitable for use with e.g. {@link FileInputStream}
 * @throws IllegalArgumentException if the URL does not correspond to a file.
 */
public static File urlToFile(final URL url) {
    return url == null ? null : urlToFile(url.toString());
}

/**
 * Converts the given URL string to its corresponding {@link File}.
 * 
 * @param url The URL to convert.
 * @return A file path suitable for use with e.g. {@link FileInputStream}
 * @throws IllegalArgumentException if the URL does not correspond to a file.
 */
public static File urlToFile(final String url) {
    String path = url;
    if (path.startsWith("jar:")) {
        // remove "jar:" prefix and "!/" suffix
        final int index = path.indexOf("!/");
        path = path.substring(4, index);
    }
    try {
        if (PlatformUtils.isWindows() && path.matches("file:[A-Za-z]:.*")) {
            path = "file:/" + path.substring(5);
        }
        return new File(new URL(path).toURI());
    }
    catch (final MalformedURLException e) {
        // NB: URL is not completely well-formed.
    }
    catch (final URISyntaxException e) {
        // NB: URL is not completely well-formed.
    }
    if (path.startsWith("file:")) {
        // pass through the URL as-is, minus "file:" prefix
        path = path.substring(5);
        return new File(path);
    }
    throw new IllegalArgumentException("Invalid URL: " + url);
}

SciJava Common 라이브러리 에서 이러한 메소드를 찾을 수 있습니다 .


5
+1; 현재까지 가장 좋은 대답 : OS에 대한 올바른 표기법을 사용하여 경로를 반환합니다. (예 : Windows의 경우).
Bathsheba

보안과 관련하여 Java WebStart가이를 허용하지 않는 것으로 나타났습니다.
Thorbjørn Ravn Andersen

55

다음을 사용할 수도 있습니다.

CodeSource codeSource = YourMainClass.class.getProtectionDomain().getCodeSource();
File jarFile = new File(codeSource.getLocation().toURI().getPath());
String jarDir = jarFile.getParentFile().getPath();

3
이것은 나를 위해 더 잘 작동합니다. 왜냐하면 그것이 수업이 아닌 항아리의 길을 제공하기 때문입니다!
T30

나도 일했다. Fab의 답변과 결합하면 더 좋아집니다!
Danielson Alves Júnior

25

ClassLoader.getResource ()를 사용하여 현재 클래스의 URL을 찾으십시오.

예를 들면 다음과 같습니다.

package foo;

public class Test
{
    public static void main(String[] args)
    {
        ClassLoader loader = Test.class.getClassLoader();
        System.out.println(loader.getResource("foo/Test.class"));
    }
}

(이 예제 는 비슷한 질문 에서 가져온 것입니다 .)

디렉토리를 찾으려면 URL을 수동으로 분리해야합니다. jar URL 형식에 대해서는 JarClassLoader 학습서 를 참조하십시오 .


내 JAR 파일이 난독 처리되었으므로이 답변으로 문제가 해결되지 않습니다. 그러나 나는 그 질문에 그것을 지정하지 않았으므로 이것은 여전히 ​​유효한 대답입니다.
Thiago Chaves

12
난독 처리 된 경우 Test.class.getName ()을 사용하고 적절한 munging을 수행하십시오.
Jon Skeet

1
@JonSkeet 귀하의 답변에 너무 많은 문제가 있습니다 : 1. NPE당신이 묻는 질문에 대한 답변을 하지 않았기 때문에 ( 아니오 JAR 디렉토리에 대한 경로가 요청되었고 당신은 전혀 다른 질문에 대답했습니다 : 수업의 경로). 2. 다른 사람들이 지적했듯이 동일한 문제가 발생했지만 애플릿에서는 작동하지 않습니다. 3. 리턴 된 경로는 정식 경로 표시가 아닙니다 jar:file:/listener/build/libs/listener-1.0.0-all.jar!/shared/Test.class..
WhiteAngel

1
@WhiteAngel : 1) 내 게시물의 마지막 줄은 URL을보고 jar 파일을 얻으려면 그 URL을 선택해야한다는 것을 나타냅니다. 2) 애플릿이 코멘트에 언급되지 않은 (... 특히 나중에 10 년) 나는 그것이 가장 완벽한 답이 아니에요 동의하지만, 나는 그것에 대해 가치 논쟁으로 정말 그렇게 나쁜 생각하지 않습니다 여기 이상하게도, 나는 돈을 - 내가 답변을 게시 한 질문에 대한 모든 답변에 대한 모든 의견을 볼 시간이 없습니다. 3) 다시, jar URL 형식으로 연결합니다.
Jon Skeet

2
@ WhiteAngel : 내가 쓴 최고의 답변입니까? 아니. 당신이 그것을 만드는 것만 큼 나쁜가요? 아니요, 그렇게 생각하지 않습니다. (특히 NPE를 던지는 것에 대한 주장에 관해서는 그렇지 않습니다.) 나는 이것에 대해 소란을 피우는 대신 자신의 대답을 추가하는 것이 좋습니다. 그것은 더 긍정적 인 접근법이 될 것입니다.
Jon Skeet

19

최근에 사용을 제안한 사람이 없다는 것이 놀랍습니다 Path. 여기에는 인용이 있습니다. " Path클래스에는 경로에 대한 정보를 얻거나, 경로의 요소에 액세스하거나, 경로를 다른 형식으로 변환하거나, 경로의 일부를 추출하는 데 사용할 수있는 다양한 방법이 포함되어 있습니다 "

따라서 좋은 대안은 다음 Path과 같이 목표 를 얻는 것입니다.

Path path = Paths.get(Test.class.getProtectionDomain().getCodeSource().getLocation().toURI());

3
참고로, Path는 Java 7부터 사용할 수 있습니다.
Chris Forrence

15

Linux, Mac 및 Windows에서 작동하는 유일한 솔루션 :

public static String getJarContainingFolder(Class aclass) throws Exception {
  CodeSource codeSource = aclass.getProtectionDomain().getCodeSource();

  File jarFile;

  if (codeSource.getLocation() != null) {
    jarFile = new File(codeSource.getLocation().toURI());
  }
  else {
    String path = aclass.getResource(aclass.getSimpleName() + ".class").getPath();
    String jarFilePath = path.substring(path.indexOf(":") + 1, path.indexOf("!"));
    jarFilePath = URLDecoder.decode(jarFilePath, "UTF-8");
    jarFile = new File(jarFilePath);
  }
  return jarFile.getParentFile().getAbsolutePath();
}

작동하지 않습니다. Linux에서 toUri () 메소드는 예외를 발생시키고 Linux의 다른 부분에는 도달하지 않습니다.
Wilhelm Sorban

9

나는 같은 문제가 있었고 그 방법으로 해결했습니다.

File currentJavaJarFile = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().getPath());   
String currentJavaJarFilePath = currentJavaJarFile.getAbsolutePath();
String currentRootDirectoryPath = currentJavaJarFilePath.replace(currentJavaJarFile.getName(), "");

나는 당신에게 도움이 되었기를 바랍니다.


하지마 URL.getPath () 파일 이름을 반환 하지 않으며 공백이있는 파일 경로와 같은 많은 환경에서 실패합니다.
VGR

9

다른 의견으로의 업그레이드는 다음과 같습니다.

jar 파일의 동일한 위치에있는 .jar 파일 외부의 상대 "폴더"사용 :

String path = 
  YourMainClassName.class.getProtectionDomain().
  getCodeSource().getLocation().getPath();

path = 
  URLDecoder.decode(
    path, 
    "UTF-8");

BufferedImage img = 
  ImageIO.read(
    new File((
        new File(path).getParentFile().getPath()) +  
        File.separator + 
        "folder" + 
        File.separator + 
        "yourfile.jpg"));

4
주의 : URLDecoder특수 문자를 해독하는 데 사용하지 않는 것이 좋습니다 . 특히, 같은 문자 +는 공백으로 잘못 디코딩됩니다. 자세한 내용은 내 답변을 참조하십시오.
ctrueden

파일 이름에 특수 문자를 사용하지 않는 것이 좋습니다.
Zon

URLDecoder이름에도 불구하고 URL이 아닌 URL 및 양식 매개 변수 이름과 값을 디코딩하기위한 것입니다.
Lorne의 후작

6

jar 파일을 실행하는 경로를 얻기 위해 위의 솔루션을 연구하고 서로 다른 차이점이있는 모든 방법을 시도했습니다. 이 코드가 Eclipse IDE에서 실행중인 경우 모두 표시된 클래스를 포함하여 파일의 경로를 찾고 찾은 경로로 표시된 파일을 열거 나 작성할 수 있어야합니다.

그러나 실행 가능한 jar 파일을 직접 또는 명령 줄을 통해 실행할 때 위의 방법에서 얻은 jar 파일의 경로가 jar 파일의 내부 경로를 제공하므로 항상 경로를 제공하므로 까다로워집니다. 같이

rsrc : project-name (아마도 메인 클래스 파일의 패키지 이름-표시된 클래스라고 말해야 할 수도 있습니다)

rsrc : ... 경로를 외부 경로로 변환 할 수 없습니다. 즉, Eclipse IDE 외부에서 jar 파일을 실행할 때 jar 파일의 경로를 가져올 수 없습니다.

Eclipse IDE 외부에서 jar 파일을 실행하는 경로를 얻는 유일한 방법은

System.getProperty("java.class.path")

이 코드 라인은 java 문서와 일부 사람들이 모든 클래스 파일의 경로를 반환한다고 말한 것처럼 실행중인 jar 파일 (리턴 경로는 작업 디렉토리가 아님)의 살아있는 경로 (파일 이름 포함)를 반환 할 수 있습니다 동일한 디렉토리에 있지만 동일한 디렉토리에 많은 jar 파일이 포함되어있는 경우 내 테스트로 실행중인 jar의 경로 만 반환합니다 (실제로 Eclipse에서 발생한 다중 경로 문제에 대해).


java.class.path여러 값을 가질 수 있습니다. 이러한 값 중 하나 는 현재 클래스가있는 디렉토리 또는 JAR 파일을 제공하지만 어느 것입니까?
Lorne의 후작

확인하고 다른 솔루션을 시도했지만 jar 파일 이름을 얻지 마십시오. 이것은 매우 간단하게 작동합니다! 고마워-+1
illa girod-vitouchkina

5

다른 답변은 디렉토리가 아닌 Jar 파일 위치 인 코드 소스를 가리키는 것으로 보입니다.

사용하다

return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile();

JAR 파일 대신 파일 시스템에서 클래스를로드하는 경우 디렉토리 일 수 있습니다 (예 : 디버깅시).
Lorne의 후작

4

Gnome 데스크탑 환경에서 스크립트를 클릭하여 항아리를 실행하면 위의 선택된 답변이 작동하지 않습니다 (스크립트 또는 터미널이 아닌).

대신 다음 솔루션이 모든 곳에서 작동한다는 것을 좋아합니다.

    try {
        return URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");
    } catch (UnsupportedEncodingException e) {
        return "";
    }

2
애플릿이나 앱에서 시도 했습니까? Java Web Start를 사용하여 시작 되었습니까? 내 이해는 두 가지 상황에서 (앱이 신뢰할지라도) 실패한다는 것입니다.
앤드류 톰슨

이 솔루션은 "."의 위치 만 반환 할 수 있습니다. JAR 파일이 아닌 위치 JAR 파일.
Lorne의 후작

주의 : URLDecoder특수 문자를 해독하는 데 사용하지 않는 것이 좋습니다 . 특히, 같은 문자 +는 공백으로 잘못 디코딩됩니다. 자세한 내용은 내 답변을 참조하십시오.
ctrueden

봄 부츠에서 던질 것입니다NullPointerException
Ravi Parekh

당신은해야합니다 NPE어떤 자원이 JAR에 존재하지 않는 경우.
WhiteAngel

3

실제로 여기에 더 나은 버전이 있습니다. 폴더 이름에 공백이 있으면 이전 버전은 실패했습니다.

  private String getJarFolder() {
    // get name and path
    String name = getClass().getName().replace('.', '/');
    name = getClass().getResource("/" + name + ".class").toString();
    // remove junk
    name = name.substring(0, name.indexOf(".jar"));
    name = name.substring(name.lastIndexOf(':')-1, name.lastIndexOf('/')+1).replace('%', ' ');
    // remove escape characters
    String s = "";
    for (int k=0; k<name.length(); k++) {
      s += name.charAt(k);
      if (name.charAt(k) == ' ') k += 2;
    }
    // replace '/' with system separator char
    return s.replace('/', File.separatorChar);
  }

애플릿에 실패하면 일반적으로 로컬 파일에 액세스 할 수 없습니다. JWS에 대해 잘 모르지만 로컬 파일을 처리하기 위해 앱을 다운로드하지 못할 수 있습니다.?


경로를 디코딩하는 몇 가지 기본 제공 방법이 있습니다. 자신의 코드를 작성할 필요가 없습니다.
Lorne의 후작

3

항아리를 사용하여 경로를 얻으려고했습니다.

String folder = MyClassName.class.getProtectionDomain().getCodeSource().getLocation().getPath();

c : \ app> java -jar application.jar

" c : \ app " 폴더의 Windows에서 "application.jar"라는 jar 응용 프로그램을 실행하면 문자열 변수 "folder"의 값이 " \ c : \ app \ application.jar "이고 테스트에 문제가있었습니다. 경로의 정확성

File test = new File(folder);
if(file.isDirectory() && file.canRead()) { //always false }

그래서 나는 "test"를 다음과 같이 정의하려고 시도했다.

String fold= new File(folder).getParentFile().getPath()
File test = new File(fold);

" \ c : \ app \ application.jar " 대신 " c : \ app " 와 같은 올바른 형식의 경로를 얻으려면 작동한다는 것을 알았습니다.


3

가장 간단한 해결책은 jar를 실행할 때 경로를 인수로 전달하는 것입니다.

쉘 스크립트 (Windows의 경우 .bat, 다른 곳에서는 .sh)를 사용하여이를 자동화 할 수 있습니다.

java -jar my-jar.jar .

나는 .현재 작업 디렉토리를 전달하는 데 사용 되었습니다.

최신 정보

jar 파일을 하위 디렉토리에 고정하여 사용자가 실수로 클릭하지 않도록 할 수 있습니다. 또한 코드는 명령 행 인수가 제공되었는지 확인하고 인수가 누락 된 경우 좋은 오류 메시지를 제공해야합니다.


3

마침내 작동하는 (짧은) 솔루션을 찾기 전에 많은 것을 엉망으로 만들어야했습니다.
이는 그 수 jarLocation유사한 프리픽스 붙어 file:\또는 jar:file\사용에 의해 제거 될 수있다 String#substring().

URL jarLocationUrl = MyClass.class.getProtectionDomain().getCodeSource().getLocation();
String jarLocation = new File(jarLocationUrl.toString()).getParent();

2
String path = getClass().getResource("").getPath();

경로는 항상 jar 파일 내의 리소스를 나타냅니다.


1
해당 경로 문자열은 여전히 ​​필요에 따라 단순화되어야합니다. String path = new File(getClass().getResource("").getPath()).getParentFile().getParent(); File jarDir = new File(path.substring(5));
ZZZ

4
모두 getResource("")getResource(".")내 시험에서 실패 클래스가 JAR 파일 내에 거주하는 경우; 두 호출 모두 null을 반환했습니다.
ctrueden

2
이것은 던진다 NullPointerException.
Lorne의 후작

2
public static String dir() throws URISyntaxException
{
    URI path=Main.class.getProtectionDomain().getCodeSource().getLocation().toURI();
    String name= Main.class.getPackage().getName()+".jar";
    String path2 = path.getRawPath();
    path2=path2.substring(1);

    if (path2.contains(".jar"))
    {
        path2=path2.replace(name, "");
    }
    return path2;}

Windows에서 잘 작동


1

실망스러운 것은 Eclipse에서 개발할 때 훌륭한 디렉토리를 MyClass.class.getProtectionDomain().getCodeSource().getLocation()반환 /bin하지만 jar로 컴파일 할 때 경로에 /myjarname.jar잘못된 파일 이름을 제공 하는 부분이 포함된다는 것 입니다.

코드가 IDE에서 작동하고 항아리로 컴파일되면 다음 코드 조각을 사용합니다.

URL applicationRootPathURL = getClass().getProtectionDomain().getCodeSource().getLocation();
File applicationRootPath = new File(applicationRootPathURL.getPath());
File myFile;
if(applicationRootPath.isDirectory()){
    myFile = new File(applicationRootPath, "filename");
}
else{
    myFile = new File(applicationRootPath.getParentFile(), "filename");
}

1

다른 것에 대해서는 확실하지 않지만 제 경우에는 "Runnable jar"와 함께 작동하지 않았으며 phchen2 답변 과이 링크에서 다른 코드를 함께 수정하여 작동하게했습니다 . 실행중인 JAR 파일의 경로를 얻는 방법? 코드:

               String path=new java.io.File(Server.class.getProtectionDomain()
                .getCodeSource()
                .getLocation()
                .getPath())
          .getAbsolutePath();
       path=path.substring(0, path.lastIndexOf("."));
       path=path+System.getProperty("java.class.path");

1

몇 가지 솔루션을 시도했지만 실행 가능한 jar이 Eclipse의 "외부 라이브러리 패키징"으로 익스포트 된 (아마도 특별한) 경우에 대한 올바른 결과를 얻지 못했습니다. 어떤 이유로 ProtectionDomain을 기반으로하는 모든 솔루션은이 경우 null이됩니다.

위의 일부 솔루션을 결합하여 다음 작업 코드를 달성했습니다.

String surroundingJar = null;

// gets the path to the jar file if it exists; or the "bin" directory if calling from Eclipse
String jarDir = new File(ClassLoader.getSystemClassLoader().getResource(".").getPath()).getAbsolutePath();

// gets the "bin" directory if calling from eclipse or the name of the .jar file alone (without its path)
String jarFileFromSys = System.getProperty("java.class.path").split(";")[0];

// If both are equal that means it is running from an IDE like Eclipse
if (jarFileFromSys.equals(jarDir))
{
    System.out.println("RUNNING FROM IDE!");
    // The path to the jar is the "bin" directory in that case because there is no actual .jar file.
    surroundingJar = jarDir;
}
else
{
    // Combining the path and the name of the .jar file to achieve the final result
    surroundingJar = jarDir + jarFileFromSys.substring(1);
}

System.out.println("JAR File: " + surroundingJar);


0

아카이브의 코드에서 호출 된이 메소드는 .jar 파일이있는 폴더를 리턴합니다. Windows 또는 Unix에서 작동해야합니다.


  private String getJarFolder() {
    String name = this.getClass().getName().replace('.', '/');
    String s = this.getClass().getResource("/" + name + ".class").toString();
    s = s.replace('/', File.separatorChar);
    s = s.substring(0, s.indexOf(".jar")+4);
    s = s.substring(s.lastIndexOf(':')-1);
    return s.substring(0, s.lastIndexOf(File.separatorChar)+1);
  } 

코드에서 파생 : JAR에서 실행 중인지 확인


3
"Windows 또는 Unix에서 작동해야합니다." 그러나 모든 애플릿과 모든 앱에서 실패합니다. JWS를 사용하여 시작했습니다.
Andrew Thompson

0

그것이 체크인 Windows되었지만 다른 운영 체제에서 완벽하게 작동한다고 생각합니다 Linux,MacOs,Solaris.


같은 디렉토리에 2 개의 .jar 파일 이있었습니다 . 한 .jar파일 .jar에서 같은 디렉토리에있는 다른 파일 을 시작하고 싶었습니다 .

문제는 cmd현재 디렉토리 에서 시작할 때 입니다 system32.


경고!

  • 아래는 내가 심지어 폴더의 이름으로 수행 한 모든 테스트에서 꽤 잘 작동하는 것 같다 ;][[;'57f2g34g87-8+9-09!2#@!$%^^&()또는()%&$%^@# 그것을 잘 작동합니다.
  • ProcessBuilder다음과 같이 아래를 사용하고 있습니다.

🍂 ..

//The class from which i called this was the class `Main`
String path = getBasePathForClass(Main.class);
String applicationPath=  new File(path + "application.jar").getAbsolutePath();


System.out.println("Directory Path is : "+applicationPath);

//Your know try catch here
//Mention that sometimes it doesn't work for example with folder `;][[;'57f2g34g87-8+9-09!2#@!$%^^&()` 
ProcessBuilder builder = new ProcessBuilder("java", "-jar", applicationPath);
builder.redirectErrorStream(true);
Process process = builder.start();

//...code

🍂 getBasePathForClass(Class<?> classs):

    /**
     * Returns the absolute path of the current directory in which the given
     * class
     * file is.
     * 
     * @param classs
     * @return The absolute path of the current directory in which the class
     *         file is.
     * @author GOXR3PLUS[StackOverFlow user] + bachden [StackOverFlow user]
     */
    public static final String getBasePathForClass(Class<?> classs) {

        // Local variables
        File file;
        String basePath = "";
        boolean failed = false;

        // Let's give a first try
        try {
            file = new File(classs.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());

            if (file.isFile() || file.getPath().endsWith(".jar") || file.getPath().endsWith(".zip")) {
                basePath = file.getParent();
            } else {
                basePath = file.getPath();
            }
        } catch (URISyntaxException ex) {
            failed = true;
            Logger.getLogger(classs.getName()).log(Level.WARNING,
                    "Cannot firgue out base path for class with way (1): ", ex);
        }

        // The above failed?
        if (failed) {
            try {
                file = new File(classs.getClassLoader().getResource("").toURI().getPath());
                basePath = file.getAbsolutePath();

                // the below is for testing purposes...
                // starts with File.separator?
                // String l = local.replaceFirst("[" + File.separator +
                // "/\\\\]", "")
            } catch (URISyntaxException ex) {
                Logger.getLogger(classs.getName()).log(Level.WARNING,
                        "Cannot firgue out base path for class with way (2): ", ex);
            }
        }

        // fix to run inside eclipse
        if (basePath.endsWith(File.separator + "lib") || basePath.endsWith(File.separator + "bin")
                || basePath.endsWith("bin" + File.separator) || basePath.endsWith("lib" + File.separator)) {
            basePath = basePath.substring(0, basePath.length() - 4);
        }
        // fix to run inside netbeans
        if (basePath.endsWith(File.separator + "build" + File.separator + "classes")) {
            basePath = basePath.substring(0, basePath.length() - 14);
        }
        // end fix
        if (!basePath.endsWith(File.separator)) {
            basePath = basePath + File.separator;
        }
        return basePath;
    }

0

이 코드는 저에게 효과적이었습니다.

private static String getJarPath() throws IOException, URISyntaxException {
    File f = new File(LicensingApp.class.getProtectionDomain().().getLocation().toURI());
    String jarPath = f.getCanonicalPath().toString();
    String jarDir = jarPath.substring( 0, jarPath.lastIndexOf( File.separator ));
    return jarDir;
  }

0

이 코드는 프로그램이 JAR 파일 또는 IDE 내에서 실행되고 있는지 식별하는 데 도움이되었습니다.

private static boolean isRunningOverJar() {
    try {
        String pathJar = Application.class.getResource(Application.class.getSimpleName() + ".class").getFile();

        if (pathJar.toLowerCase().contains(".jar")) {
            return true;
        } else {
            return false;
        }
    } catch (Exception e) {
        return false;
    }
}

JAR 파일의 Windows 전체 경로를 가져와야하는 경우이 방법을 사용하고 있습니다.

    private static String getPathJar() {
        try {
            final URI jarUriPath =
                    Application.class.getResource(Application.class.getSimpleName() + ".class").toURI();
            String jarStringPath = jarUriPath.toString().replace("jar:", "");
            String jarCleanPath  = Paths.get(new URI(jarStringPath)).toString();

            if (jarCleanPath.toLowerCase().contains(".jar")) {
                return jarCleanPath.substring(0, jarCleanPath.lastIndexOf(".jar") + 4);
            } else {
                return null;
            }
        } catch (Exception e) {
            log.error("Error getting JAR path.", e);
            return null;
        }
    }

CommandLineRunner구현을 사용하여 Spring Boot 응용 프로그램으로 작업하는 완전한 코드 는 응용 프로그램이 항상 콘솔보기 (JAR 파일 이름에서 실수로 두 번 클릭) 내에서 실행되도록하기 위해 다음 코드를 사용하고 있습니다.

@SpringBootApplication
public class Application implements CommandLineRunner {
    public static void main(String[] args) throws IOException {
        Console console = System.console();

        if (console == null && !GraphicsEnvironment.isHeadless() && isRunningOverJar()) {
            Runtime.getRuntime().exec(new String[]{"cmd", "/c", "start", "cmd", "/k",
                    "java -jar \"" + getPathJar() + "\""});
        } else {
            SpringApplication.run(Application.class, args);
        }
    }

    @Override
    public void run(String... args) {
        /*
        Additional code here...
        */
    }

    private static boolean isRunningOverJar() {
        try {
            String pathJar = Application.class.getResource(Application.class.getSimpleName() + ".class").getFile();

            if (pathJar.toLowerCase().contains(".jar")) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            return false;
        }
    }

    private static String getPathJar() {
        try {
            final URI jarUriPath =
                    Application.class.getResource(Application.class.getSimpleName() + ".class").toURI();
            String jarStringPath = jarUriPath.toString().replace("jar:", "");
            String jarCleanPath  = Paths.get(new URI(jarStringPath)).toString();

            if (jarCleanPath.toLowerCase().contains(".jar")) {
                return jarCleanPath.substring(0, jarCleanPath.lastIndexOf(".jar") + 4);
            } else {
                return null;
            }
        } catch (Exception e) {
            return null;
        }
    }
}

-1

Java 7로 작성하고 Oracle 런타임으로 Windows 7을 테스트하고 오픈 소스 런타임으로 Ubuntu를 테스트하십시오. 이것은 해당 시스템에 완벽하게 작동합니다.

실행중인 jar 파일의 부모 디렉토리 경로 (이 코드를 호출하는 클래스가 jar 아카이브 자체의 직접적인 자식이라고 가정) :

try {
    fooDir = new File(this.getClass().getClassLoader().getResource("").toURI());
} catch (URISyntaxException e) {
    //may be sloppy, but don't really need anything here
}
fooDirPath = fooDir.toString(); // converts abstract (absolute) path to a String

따라서 foo.jar의 경로는 다음과 같습니다.

fooPath = fooDirPath + File.separator + "foo.jar";

다시 말하지만 이것은 Mac 또는 이전 Windows에서 테스트되지 않았습니다.


-1

getProtectionDomain접근 방식은 때때로 일부 핵심 Java 클래스 (예 : StringBuilderIBM JDK 내의 클래스)에 대한 jar을 찾아야 할 때 작동하지 않을 수 있지만 다음과 같이 원활하게 작동합니다.

public static void main(String[] args) {
    System.out.println(findSource(MyClass.class));
    // OR
    System.out.println(findSource(String.class));
}

public static String findSource(Class<?> clazz) {
    String resourceToSearch = '/' + clazz.getName().replace(".", "/") + ".class";
    java.net.URL location = clazz.getResource(resourceToSearch);
    String sourcePath = location.getPath();
    // Optional, Remove junk
    return sourcePath.replace("file:", "").replace("!" + resourceToSearch, "");
}

URL.getPath ()는 당신이 생각하는 것을하지 않습니다. 모든 특수 문자는 퍼센트로 인코딩됩니다.
VGR 2016 년

-1

클래스의 문자열 위치를 얻는 다른 방법이 있습니다.

URL path = Thread.currentThread().getContextClassLoader().getResource("");
Path p = Paths.get(path.toURI());
String location = p.toString();

출력 문자열은

C:\Users\Administrator\new Workspace\...

공백과 다른 문자는 처리되며 형식은 없습니다 file:/. 사용하기 쉬울 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.