web-dev-qa-db-ja.com

実行中のJARファイルのパスを取得する方法

私のコードはJARファイル(foo.jarなど)の中で実行されます。コード内で、実行中のfoo.jarがどのフォルダーにあるかを知る必要があります。

したがって、foo.jarがC:\FOO\にある場合は、現在の作業ディレクトリに関係なく、そのパスを取得したいと思います。

532
Thiago Chaves
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
    .toURI()).getPath();

"MyClass"をあなたのクラスの名前に置き換えてください。

クラスがファイル以外の場所からロードされた場合、これは明らかに奇妙なことになります。

493
Zarkonnen

私にとって最良の解決策:

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

これはスペースと特殊文字に関する問題を解決するはずです。

186
Fab

特定のFileに対してClassを取得するには、2つのステップがあります。

  1. ClassURLに変換する
  2. URLFileに変換する

両方のステップを理解し、それらを混同しないことが重要です。

Fileを取得したら、getParentFileを呼び出して包含フォルダーを取得できます。それが必要な場合は可能です。

ステップ1:ClassからURL

他の回答で説明したように、URLに関連するClassを見つけるには2つの主要な方法があります。

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

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

どちらにも長所と短所があります。

getProtectionDomainアプローチは、クラスの基本位置(例えば、それを含むJARファイル)を得る。ただし、getProtectionDomain()を呼び出すときにJavaランタイムのセキュリティポリシーがSecurityExceptionをスローする可能性があるため、アプリケーションをさまざまな環境で実行する必要がある場合は、それらすべてでテストするのが最善です。

getResourceアプローチは、クラスのフルURLリソースパスを生成します。そこから追加の文字列操作を実行する必要があります。それはfile:パスかもしれませんが、OSGiフレームワーク内で実行する場合はjar:file:あるいはbundleresource://346.fwk2106232034:4/foo/Bar.classのようなもっと厄介なこともあります。逆に、getProtectionDomainのアプローチでは、OSGi内からでもfile:のURLが正しく生成されます。

クラスがJARファイル内にある場合、getResource("")getResource(".")の両方が私のテストで失敗したことに注意してください。両方の呼び出しでnullが返されました。安全であると思われるので、私は代わりに上記の#2呼び出しをお勧めします。

ステップ2:URLからFile

いずれにしても、URLを取得したら、次のステップはFileへの変換です。これはそれ自身の挑戦です。詳細については、 Kohsuke Kawaguchiさんのブログ投稿 を参照してください。つまり、URLが完全に整形式であれば、new File(url.toURI())を使用できます。

最後に、URLDecoderを使うことを 強くお勧めしません 。 URLの一部の文字、特に:および/は、有効なURLエンコード文字ではありません。 URLDecoder / Javadocから:

エンコードされた文字列内のすべての文字は、 "a"から "z"、 "A"から "Z"、 "0"から "9"、および " - "、 "_"、 "のいずれかです。 "と" * "。文字 "%"は使用できますが、特殊なエスケープシーケンスの開始として解釈されます。

...

このデコーダが違法な文字列を扱うことができる2つの可能な方法があります。不正な文字だけを残すことも、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 ライブラリにあります。

143
ctrueden

また使用することができます:

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

現在のクラスのURLを見つけるには、ClassLoader.getResource()を使用してください。

例えば:

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チュートリアル を参照してください。

24
Jon Skeet

最近誰も Path を使うことを提案していないのを見て驚いています。 「Pathクラスには、パスに関する情報の取得、パスの要素へのアクセス、パスの他の形式への変換、またはパスの一部の抽出に使用できるさまざまなメソッドが含まれています

したがって、良い代替案はPathオブジェクトを次のようにすることです。

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

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();
}
14
Dmitry Trofimov

これは他のコメントへのアップグレードです。

.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"));
8
Zon

私は同じ問題を抱えていました、そして私はそれをそのように解決しました:

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

私はあなたの助けになれば幸いです。

8
Charlie

実行中のjarファイルのパスを取得するために、私は上記の解決策を研究し、お互いにいくつかの違いが存在するすべての方法を試してみました。これらのコードがEclipse IDEで実行されている場合、それらはすべて指定されたクラスを含むファイルのパスを見つけて、見つけられたパスで示されたファイルを開くか作成することができるはずです。

しかし、実行可能なjarファイルを直接またはコマンドラインから実行すると、注意が必要です。上記の方法で取得したjarファイルのパスは、jarファイル内に内部パスを指定するため、失敗することになります。として

rsrc:project-name(おそらくメインクラスファイルのパッケージ名 - 指定されたクラスだと言うべきです)

Rsrc:...パスを外部パスに変換することはできません。つまり、Eclipse IDEの外部でjarファイルを実行すると、jarファイルのパスを取得できません。

Eclipseの外部でjarファイルを実行するパスを取得する唯一の方法は、[IDEです。

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

このコード行は、実行中のjarファイルの生存パス(ファイル名を含む)を返す場合があります(戻りパスは作業ディレクトリではないことに注意してください)。Java文書や一部の人々は、すべてのクラスファイルのパスを返す同じディレクトリにありますが、同じディレクトリにたくさんのjarファイルが含まれている場合のテストでは、実行中のjarのパスのみが返されます(実際にはEclipseで発生した複数パスの問題について)。

6
phchen2

gnomeデスクトップ環境から(スクリプトや端末からではなく)クリックしてjarを実行した場合、上記の選択された答えは機能しません。

代わりに、私は以下の解決策が至るところで働いているのが好きです:

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

最も簡単な解決策は、jarを実行するときにパスを引数として渡すことです。

これはシェルスクリプト(Windowsでは.bat、それ以外の場所では.sh)を使って自動化できます。

Java -jar my-jar.jar .

現在の作業ディレクトリを渡すために.を使用しました。

_アップデート_

ユーザーが誤ってクリックしないように、jarファイルをサブディレクトリに固定することをお勧めします。あなたのコードは、コマンドライン引数が与えられていることを確かめるためにチェックし、引数が欠けているなら良いエラーメッセージを提供するべきです。

3
Max Heiber

私がやっと実用的な(そして短い)解決策を見つける前に、私はたくさんいじらなければなりませんでした。
jarLocationfile:\jar:file\のような接頭辞が付いている可能性がありますが、これらはString#substring()を使用して削除できます。

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

実際にはこれがより良いバージョンです - フォルダ名にスペースがある場合、古いバージョンは失敗しました。

  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についてはあまり知りませんが、ローカルファイルを処理するためにアプリをダウンロードすることは不可能かもしれません。

3
bacup lad

他の回答は、ディレクトリではないJarファイルの場所であるコードソースを指しているようです。

つかいます

return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile();
3
F.O.O
String path = getClass().getResource("").getPath();

パスは常にjarファイル内のリソースを参照します。

2
ZZZ

私はを使用してjarの実行パスを取得しようとしました

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

c:\ app> Java -jar application.jar

Windowsでフォルダー " c:\ app "の "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 "のような正しい形式でパスを取得すると、うまくいくことがわかりました。

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上でうまく動作する

2
Denton

他の人についてはよくわかりませんが、私の場合は "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
Fahad Alkamli

イライラしているのは、Eclipseで開発しているときにMyClass.class.getProtectionDomain().getCodeSource().getLocation()が素晴らしい/binディレクトリを返すことですが、jarにコンパイルすると、パスに不正なファイル名が含まれる/myjarname.jar部分が含まれることです。

コードが理想の中で動作するようにするために、そしてそれがjarにコンパイルされたら、私は次のコードを使用します。

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
Alexander

いくつかの解決策を試してみましたが、実行可能なjarファイルがEclipseの "Packaging external libraries"でエクスポートされている(おそらく特別な)ケースに対して正しい結果が得られませんでした。何らかの理由で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);
1
DragonGamer

アーカイブ内のコードから呼び出されるこのメソッドは、.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から実行するかどうかを決定します

0
Bacup Lad

これを試して:

String path = new File("").getAbsolutePath();
0
Blarzek

これはWindowsでのみチェックされますが、他のオペレーティングシステムでも完璧に動作すると思います[Linux,MacOs,Solaris] :)。


同じディレクトリに 2 .jarファイルがありました。 1つの.jarファイルから、同じディレクトリーにあるもう1つの.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
GOXR3PLUS

このコードは私にとって役に立ちました:

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
John Lockwood