Question Comment obtenir le chemin d'un fichier JAR en cours d'exécution?


Mon code s'exécute dans un fichier JAR, disons foo.jar, et j'ai besoin de savoir, dans le code, dans quel dossier est lancé le foo.jar.

Donc, si foo.jar est dans C:\FOO\, Je veux obtenir ce chemin quel que soit mon répertoire de travail actuel.


482
2017-11-26 12:30


origine


Réponses:


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

Remplacer "MyClass" avec le nom de votre classe

Evidemment, cela fera des choses bizarres si votre classe a été chargée depuis un emplacement autre que celui du fichier.


446
2017-11-26 12:50



Meilleure solution pour moi:

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

Cela devrait résoudre le problème des espaces et des caractères spéciaux.


176
2017-07-27 18:22



Pour obtenir le File pour un donné Class, il y a deux étapes:

  1. Convertir le Class à un URL
  2. Convertir le URL à un File

Il est important de comprendre les deux étapes et de ne pas les confondre.

Une fois que vous avez le File, tu peux appeler getParentFile pour obtenir le dossier contenant, si c'est ce dont vous avez besoin.

Étape 1: Class à URL

Comme on l’a vu dans d’autres réponses, il existe deux moyens principaux de URL pertinent pour un Class.

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

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

Les deux ont des avantages et des inconvénients.

le getProtectionDomain approche donne l’emplacement de base de la classe (par exemple, le fichier JAR contenant). Cependant, il est possible que la stratégie de sécurité du runtime Java lance SecurityException en appelant getProtectionDomain(), donc si votre application doit fonctionner dans une variété d'environnements, il est préférable de tester dans chacun d'eux.

le getResource L'approche fournit le chemin complet de la ressource URL de la classe, à partir de laquelle vous devrez effectuer une manipulation de chaîne supplémentaire. Ce peut être un file: chemin, mais il pourrait aussi être jar:file: ou même quelque chose de plus méchant comme bundleresource://346.fwk2106232034:4/foo/Bar.class lors de l'exécution dans un environnement OSGi. Inversement, le getProtectionDomain approche donne correctement un file: URL même depuis OSGi.

Notez que les deux getResource("") et getResource(".") échoué dans mes tests, lorsque la classe résidait dans un fichier JAR; les deux invocations ont renvoyé null. Je recommande donc l'invocation n ° 2 ci-dessus, car elle semble plus sûre.

Étape 2: URL à File

De toute façon, une fois que vous avez un URL, l'étape suivante est la conversion en File. C'est son propre défi; voir Le blog de Kohsuke Kawaguchi à ce sujet pour plus de détails, mais en bref, vous pouvez utiliser new File(url.toURI()) tant que l'URL est complètement bien formée.

Enfin, je voudrais fortement décourager en utilisant URLDecoder. Quelques caractères de l'URL, : et / en particulier, ne sont pas des caractères encodés en URL valides. Du URLDecoder Javadoc:

On suppose que tous les caractères de la chaîne codée sont l'un des suivants: "a" à "z", "A" à "Z", "0" à "9" et "-", "_", " .", et "*". Le caractère "%" est autorisé mais est interprété comme le début d'une séquence d'échappement spéciale.

...

Il y a deux façons possibles pour ce décodeur de traiter des chaînes illégales. Il peut soit laisser des caractères illégaux seuls, soit lancer une exception IllegalArgumentException. La démarche du décodeur est laissée à l'implémentation.

En pratique, URLDecoder ne jette généralement pas IllegalArgumentException comme menacé ci-dessus. Et si votre chemin de fichier a des espaces codés comme %20, cette approche peut sembler fonctionner. Toutefois, si votre chemin de fichier comporte d’autres caractères non alphamériques tels que + vous aurez des problèmes avec URLDecoder mangling votre chemin de fichier.

Code de travail

Pour réaliser ces étapes, vous pourriez avoir des méthodes comme celles-ci:

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

Vous pouvez trouver ces méthodes dans le SciJava Common bibliothèque:


135
2017-10-04 18:08



Vous pouvez aussi utiliser:

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

44
2017-08-14 23:33



Utilisez ClassLoader.getResource () pour trouver l'URL de votre classe actuelle.

Par exemple:

package foo;

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

(Cet exemple tiré de une question similaire.)

Pour trouver le répertoire, vous devez ensuite séparer l'URL manuellement. Voir le JarClassLoader tutoriel pour le format d'une URL jar.


23
2017-11-26 12:34



Je suis surpris de voir qu'aucun d'entre eux n'a récemment proposé d'utiliser Path. Voici une citation: "le Path class comprend diverses méthodes pouvant être utilisées pour obtenir des informations sur le chemin, accéder aux éléments du chemin, convertir le chemin vers d'autres formes ou extraire des parties d'un chemin"

Ainsi, une bonne alternative consiste à obtenir le Path objest comme:

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

16
2017-08-28 08:04



La seule solution qui fonctionne pour moi sur Linux, Mac et 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();
}

12
2017-08-20 17:41



J'ai eu le même problème et je l'ai résolu comme ça:

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

J'espère que je t'ai aidé.


6
2018-05-27 14:10



Voici la mise à niveau vers d'autres commentaires, qui me semblent incomplets pour les spécificités de

en utilisant un "dossier" relatif en dehors du fichier .jar (dans le même fichier jar)   emplacement):

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"));

6
2018-03-29 11:27



La réponse sélectionnée ci-dessus ne fonctionne pas si vous exécutez votre jar en cliquant dessus depuis l'environnement de bureau Gnome (et non depuis un script ou un terminal).

Au lieu de cela, j'ai aimé que la solution suivante fonctionne partout:

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

5
2017-09-28 07:26



Pour obtenir le chemin du fichier jar en cours d'exécution, j'ai étudié les solutions ci-dessus et essayé toutes les méthodes existantes. Si ces codes s'exécutent dans Eclipse IDE, ils devraient tous être capables de trouver le chemin du fichier, y compris la classe indiquée, et d'ouvrir ou de créer un fichier indiqué avec le chemin trouvé.

Mais il est difficile, lorsque vous exécutez le fichier jar exécutable directement ou via la ligne de commande, il échouera car le chemin du fichier jar obtenu à partir des méthodes ci-dessus donnera un chemin interne dans le fichier jar, c'est-à-dire qu'il donne toujours un chemin comme

rsrc: nom-projet (je devrais peut-être dire que c'est le nom du paquet du fichier de classe principal - la classe indiquée)

Je ne peux pas convertir le chemin d'accès rsrc: ... vers un chemin externe, c'est-à-dire que lorsque vous exécutez le fichier jar en dehors de l'IDE Eclipse, il ne peut pas obtenir le chemin du fichier jar.

La seule façon possible d'obtenir le chemin d'exécution du fichier JAR en dehors d'Eclipse IDE est

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

cette ligne de code peut renvoyer le chemin de vie (y compris le nom de fichier) du fichier JAR en cours d'exécution (notez que le chemin de retour n'est pas le répertoire de travail), le document java et certaines personnes indiquant qu'il retournera les chemins de tous les fichiers de classe dans le même répertoire, mais comme mes tests si dans le même répertoire incluent de nombreux fichiers jar, ils ne renvoient que le chemin de jar en cours d'exécution (à propos des problèmes de chemins multiples en effet cela s'est passé dans l'Eclipse).


5
2017-11-02 08:13