615

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

したがって、foo.jarが にある場合C:\FOO\、現在の作業ディレクトリが何であってもそのパスを取得したいと考えています。

4

33 に答える 33

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

「MyClass」をクラスの名前に置き換えます。

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

于 2008-11-26T12:50:03.103 に答える
197

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

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

これにより、スペースと特殊文字の問題が解決されるはずです。

于 2011-07-27T18:22:41.537 に答える
167

File特定の の を取得するには、次Classの 2 つの手順があります。

  1. を に変換ClassするURL
  2. を に変換URLするFile

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

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

ステップ 1:ClassURL

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

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

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

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

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

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

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

ステップ 2:URLFile

いずれにせよ、 を取得したらURL、次のステップは に変換することFileです。これは独自の課題です。詳細については、 Kohsuke Kawaguchi のブログ投稿を参照してください。ただし、要するに、new File(url.toURI())URL が完全に整形式である限り使用できます。

最後に、 を使用しないことを強くお勧め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ライブラリにあります。

于 2012-10-04T18:08:00.883 に答える
26

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

于 2008-11-26T12:34:31.247 に答える
21

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

したがって、次のようにオブジェクトを取得することをPathお勧めします。

Path path = Paths.get(Test.class.getProtectionDomain().getCodeSource().getLocation().toURI());
于 2013-08-28T08:04:04.460 に答える
10

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

.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"));
于 2012-03-29T11:27:28.613 に答える
10

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

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

お役に立てば幸いです。

于 2013-05-27T14:10:01.783 に答える
7

実行中のjarファイルのパスを取得するために、上記のソリューションを調査し、互いにいくつかの違いがあるすべての方法を試しました。これらのコードが Eclipse IDE で実行されている場合、それらはすべて、指定されたクラスを含むファイルのパスを見つけ、見つかったパスで指定されたファイルを開くか作成できるはずです。

ただし、実行可能なjarファイルを直接またはコマンドラインから実行すると、上記の方法から取得したjarファイルのパスがjarファイルの内部パスを提供するため、失敗します。つまり、常にパスを提供します。なので

rsrc:project-name (メイン クラス ファイルのパッケージ名と言うべきかもしれません - 示されたクラス)

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

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

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

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

于 2015-11-02T08:13:09.343 に答える
6

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

使用する

return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile();
于 2016-06-10T11:57:39.353 に答える
4

Gnomeデスクトップ環境から(スクリプトや端末からではなく)クリックしてjarを実行すると、上記で選択した回答は機能しません。

代わりに、次のソリューションがどこでも機能していることを気に入っています。

    try {
        return URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");
    } catch (UnsupportedEncodingException e) {
        return "";
    }
于 2011-09-28T07:26:48.177 に答える
4

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

URL jarLocationUrl = MyClass.class.getProtectionDomain().getCodeSource().getLocation();
String jarLocation = new File(jarLocationUrl.toString()).getParent();
于 2016-08-30T13:58:45.867 に答える
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 についてはよくわかりませんが、ローカル ファイルを処理するには、アプリをダウンロードできないのではないでしょうか。

于 2011-04-15T14:30:48.803 に答える
3

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

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

java -jar my-jar.jar .

以前.は現在の作業ディレクトリを渡していました。

アップデート

ユーザーが誤ってクリックしないように、jar ファイルをサブディレクトリに貼り付けることができます。また、コードは、コマンド ライン引数が指定されていることを確認し、引数が欠落している場合は適切なエラー メッセージを提供する必要があります。

于 2015-10-20T16:57:15.263 に答える
2
String path = getClass().getResource("").getPath();

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

于 2010-11-15T21:40:10.810 に答える
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");
于 2016-06-21T15:57:17.680 に答える
1

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

コードを ide と 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");
}
于 2015-12-14T06:34:54.003 に答える
-1

getProtectionDomainたとえば、一部のコア Java クラス (たとえば、私の場合StringBuilderは IBM 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, "");
}
于 2015-05-14T18:02:19.523 に答える
-1

クラスの文字列の場所を取得する別の方法があります。

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

出力文字列は次の形式になります。

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

スペースやその他の文字は処理され、file:/. そのため、より使いやすくなります。

于 2015-05-21T18:41:50.367 に答える
-1

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

于 2011-04-14T18:09:18.963 に答える