653 Stimmen

Wie erhält man den Pfad einer laufenden JAR-Datei?

Mein Code wird innerhalb einer JAR-Datei ausgeführt, zum Beispiel foo.jar und ich muss im Code wissen, in welchem Ordner die laufenden foo.jar ist.

Also, wenn foo.jar está en C:\FOO\ Ich möchte diesen Pfad unabhängig von meinem aktuellen Arbeitsverzeichnis erhalten.

608voto

Zarkonnen Punkte 21817
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
    .toURI()).getPath();

Ersetzen Sie "MyClass" durch den Namen Ihrer Klasse.

Natürlich wird dies seltsame Dinge tun, wenn Ihre Klasse von einem anderen Ort als einer Datei geladen wurde.

200voto

Fab Punkte 1995

Die beste Lösung für mich:

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

Damit sollte das Problem mit Leerzeichen und Sonderzeichen gelöst sein.

177voto

ctrueden Punkte 6581

Um die File für eine bestimmte Class gibt es zwei Schritte:

  1. Konvertieren Sie die Class zu einer URL
  2. Konvertieren Sie die URL zu einer File

Es ist wichtig, beide Schritte zu verstehen und sie nicht miteinander zu vermischen.

Sobald Sie die File können Sie anrufen getParentFile um den enthaltenen Ordner zu erhalten, falls Sie diesen benötigen.

Schritt 1: Class a URL

Wie bereits in anderen Antworten erörtert, gibt es zwei Hauptmöglichkeiten, eine URL relevant für eine Class .

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

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

Beide haben Vor- und Nachteile.

Le site getProtectionDomain Ansatz liefert den Basisort der Klasse (z. B. die enthaltende JAR-Datei). Es ist jedoch möglich, dass die Sicherheitsrichtlinien der Java-Laufzeitumgebung SecurityException beim Aufruf von getProtectionDomain() Wenn Ihre Anwendung also in verschiedenen Umgebungen laufen muss, ist es am besten, sie in allen Umgebungen zu testen.

Le site getResource Ansatz liefert den vollständigen URL-Ressourcenpfad der Klasse, von dem aus Sie zusätzliche Stringmanipulationen vornehmen müssen. Es kann sich um eine file: Pfad, aber es könnte auch sein jar:file: oder sogar etwas Unangenehmeres wie bundleresource://346.fwk2106232034:4/foo/Bar.class wenn sie innerhalb eines OSGi-Frameworks ausgeführt werden. Umgekehrt ist die getProtectionDomain Ansatz führt korrekt zu einer file: URL auch innerhalb von OSGi.

Beachten Sie, dass beide getResource("") y getResource(".") schlug in meinen Tests fehl, wenn sich die Klasse in einer JAR-Datei befand; beide Aufrufe gaben null zurück. Daher empfehle ich stattdessen den oben gezeigten Aufruf Nr. 2, da er sicherer zu sein scheint.

Schritt 2: URL a File

Wie auch immer, sobald Sie eine URL ist der nächste Schritt die Umwandlung in eine File . Dies ist eine Herausforderung für sich; siehe Kohsuke Kawaguchis Blogbeitrag dazu für alle Einzelheiten, aber kurz gesagt, können Sie new File(url.toURI()) solange die URL vollständig wohlgeformt ist.

Schließlich würde ich stark abschrecken mit URLDecoder . Einige Zeichen der URL, : y / sind insbesondere keine gültigen URL-kodierten Zeichen. Vom URLDecoder Javadoc:

Es wird davon ausgegangen, dass alle Zeichen in der kodierten Zeichenfolge eines der folgenden sind: "a" bis "z", "A" bis "Z", "0" bis "9", und "-", "_", "." und "*". Das Zeichen "%" ist zulässig, wird aber als Beginn einer speziellen escapeten Sequenz interpretiert.

...

Es gibt zwei Möglichkeiten, wie dieser Decoder mit illegalen Zeichenfolgen umgehen kann. Entweder lässt er illegale Zeichen in Ruhe oder er löst eine IllegalArgumentException aus. Welchen Ansatz der Decoder wählt, bleibt der Implementierung überlassen.

In der Praxis, URLDecoder wirft im Allgemeinen nicht IllegalArgumentException wie oben angedroht. Und wenn Ihr Dateipfad Leerzeichen enthält, kodiert als %20 kann dieser Ansatz scheinbar funktionieren. Wenn Ihr Dateipfad jedoch andere nicht-alphanumerische Zeichen enthält, wie z. B. + werden Sie Probleme haben mit URLDecoder Ihren Dateipfad zu verfälschen.

Arbeitscode

Um diese Schritte zu erreichen, stehen Ihnen möglicherweise Methoden wie die folgenden zur Verfügung:

/**
 * 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);
}

Sie finden diese Methoden in der SciJava Allgemein Bibliothek:

71voto

Benny Neugebauer Punkte 45468

Sie können auch verwenden:

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

27voto

Jon Skeet Punkte 1325502

Verwenden Sie ClassLoader.getResource(), um die URL für Ihre aktuelle Klasse zu finden.

Zum Beispiel:

package foo;

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

(Dieses Beispiel stammt aus eine ähnliche Frage .)

Um das Verzeichnis zu finden, müssen Sie dann die URL manuell auseinandernehmen. Siehe die JarClassLoader-Anleitung für das Format einer jar-URL.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X