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

580

Mon code s'exécute dans un fichier JAR, par exemple foo.jar , et j'ai besoin de savoir, dans le code, dans quel dossier se trouve foo.jar .

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

Thiago Chaves
la source
Voir la réponse de Fab pour une solution qui fonctionne lorsque les chemins incluent des espaces. Notez également que certaines réponses ci-dessous traitent de la question dans le titre (chemin du fichier jar), certaines répondent à la question elle-même (chemin du dossier contenant le fichier jar) et certaines fournissent des chemins d'accès aux classes à l'intérieur du fichier jar.
Andy Thomas
32
Attention lors de l'utilisation dans ANT! ============== J'appelle String path = SomeClass.class.getProtectionDomain (). GetCodeSource (). GetLocation (). GetPath (); et obtenez: /C:/apache-ant-1.7.1/lib/ant.jar Pas très utile!
Dino Fancellu
Intéressant. Le code d'origine dans lequel j'ai utilisé ceci n'a jamais été exécuté dans ant, donc ce n'est pas un problème pour moi.
Thiago Chaves
2
@Dino Fancellu, j'ai vécu exactement ce que vous avez décrit. Fonctionne pendant le développement, échoue lorsqu'il est construit dans un pot.
Buddy

Réponses:

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

Remplacez "MyClass" par le nom de votre classe.

Évidemment, cela fera des choses étranges si votre classe a été chargée à partir d'un emplacement non-fichier.

Zarkonnen
la source
43
Cette toURI()étape est essentielle pour éviter les problèmes avec les caractères spéciaux, y compris les espaces et les avantages. La ligne droite correcte est: L' return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI()); utilisation URLDecoderne fonctionne pas pour de nombreux caractères spéciaux. Voir ma réponse ci-dessous pour plus de détails.
ctrueden
4
Remarque: cela renvoie le chemin d'accès, y compris le nom du fichier jar
Buddy
8
Cela ne pointe-t-il pas vers le fichier jar, au lieu du répertoire en cours d'exécution? Vous devrez faire un sur le résultat getParentFile () pour ce travail.
FOO
1
Aussi, getProtectionDomainest nul si vous obtenez votre classe à partir d'une piste de suivi:val strace = Thread.currentThread().getStackTrace; val path = strace(1).getClass.getProtectionDomain
bbarker
1
Utilisation de cette méthode avec jusqu'à Java 8; en plaçant cette méthode dans une classe qui se trouve dans un Jar externe, chargée via class-path, le chemin du pot externe sera donné à la place du Jar en cours d'exécution.
Mr00Anderson
189

La 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 avec les espaces et les caractères spéciaux.

Fab
la source
8
Une autre remarque: lors de l'appel de cette fonction à partir du Jar, le nom du pot est ajouté à la fin pour moi, donc j'ai dû exécuter: path.substring (0, path.lastIndexOf ("/") + 1);
will824
11
/ n'est pas nécessairement le séparateur de chemin. Vous devriez faire (nouveau File (path)). GetParentFile (). GetPath () à la place.
pjz
10
Aucun problème avec le nom du fichier JAR ajouté ici. La conversion UTF semble être la solution parfaite en combinaison avec @Iviggiani one ( URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");) sous Linux. Cependant, je n'ai pas essayé sous Windows.
ubuntudroid
2
Merci, cela m'a permis de charger des fichiers externes à mon JAR avec FileInputStream sous Linux et Windows. Juste eu à ajouter le chemin décodé devant le nom de fichier ...
giorgio79
11
Attention: il n'est pas recommandé d'utiliser URLDecoderpour décoder les caractères spéciaux. En particulier, des personnages comme +seront décodés par erreur dans les espaces. Voir ma réponse pour plus de détails.
ctrueden
153

Pour obtenir le Filepour une donnée Class, il y a deux étapes:

  1. Convertissez le ClassenURL
  2. Convertissez le URLenFile

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

Une fois que vous avez le File, vous pouvez appeler getParentFilepour obtenir le dossier contenant, si c'est ce dont vous avez besoin.

Étape 1: ClasspourURL

Comme indiqué dans d'autres réponses, il existe deux façons principales de trouver un URLélément pertinent pour a 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.

L' getProtectionDomainapproche donne l'emplacement de base de la classe (par exemple, le fichier JAR contenant). Cependant, il est possible que la politique de sécurité du runtime Java se SecurityExceptiondéclenche lors de l'appel getProtectionDomain(), donc si votre application doit s'exécuter dans une variété d'environnements, il est préférable de tester dans chacun d'eux.

L' getResourceapproche produit le chemin d'accès complet aux ressources URL de la classe, à partir de laquelle vous devrez effectuer une manipulation de chaîne supplémentaire. Il peut s'agir d'un file:chemin, mais il peut également l'être jar:file:ou même quelque chose de plus méchant comme bundleresource://346.fwk2106232034:4/foo/Bar.classlors de l'exécution dans un cadre OSGi. Inversement, l' getProtectionDomainapproche produit correctement une file:URL même depuis OSGi.

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

Étape 2: URLpourFile

Quoi qu'il en soit, une fois que vous avez un URL, l'étape suivante est convertie en a 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 l'utiliser new File(url.toURI())tant que l'URL est complètement bien formée.

Enfin, je découragerais fortement l' utilisation URLDecoder. Certains caractères de l'URL, :et /en particulier, ne sont pas des caractères codés URL valides. Depuis l' URLDecoder Javadoc:

Il est supposé 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 existe deux façons possibles pour ce décodeur de traiter les chaînes illégales. Il peut soit laisser les caractères illégaux seuls, soit lever une exception IllegalArgumentException. L'approche adoptée par le décodeur est laissée à la mise en œuvre.

En pratique, URLDecoderne jette généralement pas IllegalArgumentExceptioncomme menacé ci-dessus. Et si votre chemin d'accès au fichier comporte des espaces codés en tant que %20, cette approche peut sembler fonctionner. Cependant, si votre chemin d'accès au fichier contient d'autres caractères non alphamériques tels que +vous aurez des problèmes avec la URLDecodermodification de votre chemin d'accès au fichier.

Code de travail

Pour réaliser ces étapes, vous pouvez avoir des méthodes comme les suivantes:

/**
 * 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 la bibliothèque commune de SciJava :

ctrueden
la source
5
+1; la meilleure réponse à ce jour: il retournera le chemin en utilisant la notation correcte pour l'OS. (par exemple \ pour Windows).
Bathsheba
En ce qui concerne la sécurité, je pense avoir trouvé que Java WebStart ne le permettait pas.
Thorbjørn Ravn Andersen
55

Vous pouvez aussi utiliser:

CodeSource codeSource = YourMainClass.class.getProtectionDomain().getCodeSource();
File jarFile = new File(codeSource.getLocation().toURI().getPath());
String jarDir = jarFile.getParentFile().getPath();
Benny Neugebauer
la source
3
Cela fonctionne mieux pour moi, car cela donne le chemin du pot, pas de la classe!
T30
A aussi fonctionné pour moi. Combinez avec la réponse de Fab et ça s'améliore!
Danielson Alves Júnior
25

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é d' une question similaire .)

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

Jon Skeet
la source
Mon fichier JAR est obscurci, donc cette réponse ne résout pas mon problème. Mais je n'ai pas précisé cela dans la question, c'est donc toujours une réponse valable.
Thiago Chaves
12
S'il est obscurci, utilisez Test.class.getName () et effectuez le munging approprié.
Jon Skeet
1
@ JonSkeet il y a tellement de problèmes avec votre réponse: 1. Il n'y en aura pas NPEparce que vous n'avez pas répondu à la question qui a été posée (le chemin vers le répertoire JAR a été demandé et vous avez répondu sur une question absolument différente: chemin vers la classe). 2. Comme indiqué par d'autres, et j'ai eu le même problème, cela ne fonctionne pas pour les applets. 3. chemin retour ne soit pas la représentation canonique de chemin du tout: jar:file:/listener/build/libs/listener-1.0.0-all.jar!/shared/Test.class.
WhiteAngel
1
@WhiteAngel: 1) La dernière ligne de mon message indique que vous devez regarder l'URL et la séparer pour obtenir le fichier jar. Je suis d'accord que ce n'est pas la réponse la plus complète, mais je ne pense pas que ce soit vraiment si mauvais de valoir la peine (surtout 10 ans plus tard ...) 2) Les applets n'étaient pas mentionnées dans les commentaires ici - curieusement, je ne 'ai pas le temps de regarder tous les commentaires sur toutes les réponses aux questions auxquelles il m'est arrivé de poster une réponse. 3) Encore une fois, je fais un lien vers le format de l'URL du pot.
Jon Skeet
2
@WhiteAngel: Est-ce la meilleure réponse que j'ai jamais écrite? Nan. Est-ce aussi mauvais que vous le prétendez? Non je ne pense pas. (En particulier en ce qui concerne les affirmations que vous avez faites autour de lui en lançant un NPE, ce qui n'est pas le cas.) Je vous suggère d'ajouter votre propre réponse au lieu de faire des histoires à ce sujet. Ce serait une approche plus positive.
Jon Skeet
19

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

Ainsi, une bonne alternative consiste à obtenir l' Pathobjest comme:

Path path = Paths.get(Test.class.getProtectionDomain().getCodeSource().getLocation().toURI());
mat_boy
la source
3
Remarque: Path est disponible à partir de Java 7.
Chris Forrence
15

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();
}
Dmitry Trofimov
la source
Cela ne fonctionnera pas. Si sous Linux, la méthode toUri () lèvera une exception, et vous n'atteindrez pas la partie else, pour linux.
Wilhelm Sorban
9

J'ai eu le même problème et je l'ai résolu de cette façon:

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é.

Charlie
la source
Ne fais pas ça. URL.getPath () ne renvoie pas de nom de fichier et il échouera dans de nombreuses circonstances, telles que les chemins d'accès aux fichiers contenant des espaces.
VGR
9

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 (au même emplacement du pot):

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"));
Zon
la source
4
Attention: il n'est pas recommandé d'utiliser URLDecoderpour décoder les caractères spéciaux. En particulier, des personnages comme +seront décodés par erreur dans les espaces. Voir ma réponse pour plus de détails.
ctrueden
L'utilisation de caractères spéciaux dans les noms de fichiers n'est pas recommandée.
Zon
URLDecoder, malgré son nom, sert au décodage des URL et des noms et valeurs des paramètres de formulaire, et non des URL.
Marquis de Lorne
6

Pour obtenir le chemin de l'exécution du fichier jar, j'ai étudié les solutions ci-dessus et essayé toutes les méthodes qui existent quelque part. Si ces codes s'exécutent dans Eclipse IDE, ils devraient tous pouvoir trouver le chemin du fichier, y compris la classe indiquée, et ouvrir ou 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: project-name (peut-être devrais-je dire que c'est le nom du package du fichier de classe principale - la classe indiquée)

Je ne peux pas convertir le chemin rsrc: ... en 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.

Le seul moyen possible d'obtenir le chemin d'exécution du fichier jar en dehors de l'IDE Eclipse est

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

cette ligne de code peut renvoyer le chemin vivant (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), car le document java et certaines personnes ont dit qu'il retournerait 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, il ne renvoie que le chemin de l'exécution du jar (à propos du problème des chemins multiples, il est en effet arrivé dans Eclipse).

phchen2
la source
java.class.pathpeut être à plusieurs valeurs. L'une de ces valeurs fournira certainement le répertoire ou le fichier JAR où se trouve la classe actuelle, mais lequel?
Marquis de Lorne
Je confirme, j'ai essayé d'autres solutions, mais je n'obtiens jamais le nom du fichier jar. Cela fonctionne très simplement! merci - +1
guillaume girod-vitouchkina
5

D'autres réponses semblent pointer vers la source de code qui est l'emplacement du fichier Jar qui n'est pas un répertoire.

Utilisation

return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile();
FOO
la source
Il peut s'agir d'un répertoire, si vous chargez vos classes à partir d'un système de fichiers au lieu d'un fichier JAR, par exemple lors du débogage.
Marquis de Lorne
4

la réponse sélectionnée ci-dessus ne fonctionne pas si vous exécutez votre bocal en cliquant dessus depuis l'environnement de bureau Gnome (pas 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 "";
    }
lviggiani
la source
2
Avez-vous essayé cela dans une applet ou une application. lancé à l'aide de Java Web Start? Ma compréhension est qu'elle échouera dans les deux situations (même si l'application est fiable).
Andrew Thompson
Cette solution ne peut renvoyer que l'emplacement de "." dans le fichier JAR, pas l'emplacement du fichier JAR.
Marquis de Lorne
Attention: il n'est pas recommandé d'utiliser URLDecoderpour décoder les caractères spéciaux. En particulier, des personnages comme +seront décodés par erreur dans les espaces. Voir ma réponse pour plus de détails.
ctrueden
Dans Spring boot, il jetteraNullPointerException
Ravi Parekh
Vous en aurez NPEs'il n'y a pas de ressources dans JAR.
WhiteAngel
3

En fait, voici une meilleure version - l'ancienne a échoué si un nom de dossier avait un espace.

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

Quant à l'échec des applets, vous n'auriez généralement pas accès aux fichiers locaux de toute façon. Je ne connais pas grand-chose à JWS, mais pour gérer les fichiers locaux, il pourrait ne pas être possible de télécharger l'application.?

bacup lad
la source
Il existe plusieurs façons intégrées de décoder le chemin. Pas besoin d'écrire votre propre code.
Marquis de Lorne
3

J'ai essayé d'obtenir le chemin du pot en utilisant

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

c: \ app> java -jar application.jar

En exécutant l'application jar nommée "application.jar", sous Windows dans le dossier " c: \ app ", la valeur de la variable String "folder" était " \ c: \ app \ application.jar " et j'ai eu des problèmes de test pour correction du chemin

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

J'ai donc essayé de définir "test" comme:

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

pour obtenir le chemin dans un format correct comme " c: \ app " au lieu de " \ c: \ app \ application.jar " et j'ai remarqué que cela fonctionne.

TheGreatPsychoticBunny
la source
3

La solution la plus simple consiste à passer le chemin en argument lors de l'exécution du bocal.

Vous pouvez automatiser cela avec un script shell (.bat sous Windows, .sh n'importe où ailleurs):

java -jar my-jar.jar .

J'ai utilisé .pour passer le répertoire de travail actuel.

MISE À JOUR

Vous voudrez peut-être coller le fichier jar dans un sous-répertoire afin que les utilisateurs ne cliquent pas accidentellement dessus. Votre code doit également vérifier que les arguments de ligne de commande ont été fournis et fournir un bon message d'erreur si les arguments sont manquants.

Max Heiber
la source
3

J'ai dû beaucoup m'amuser avant de trouver enfin une solution (et courte) de travail.
Il est possible que le jarLocationsoit accompagné d'un préfixe comme file:\ou jar:file\, qui peut être supprimé à l'aide de String#substring().

URL jarLocationUrl = MyClass.class.getProtectionDomain().getCodeSource().getLocation();
String jarLocation = new File(jarLocationUrl.toString()).getParent();
Jelle
la source
2
String path = getClass().getResource("").getPath();

Le chemin fait toujours référence à la ressource dans le fichier jar.

ZZZ
la source
1
Cette chaîne de chemin doit encore être simplifiée selon vos besoins. String path = new File(getClass().getResource("").getPath()).getParentFile().getParent(); File jarDir = new File(path.substring(5));
ZZZ
4
Les deux getResource("")et ont getResource(".")échoué dans mes tests, lorsque la classe résidait dans un fichier JAR; les deux invocations ont retourné null.
ctrueden
2
Cela jette NullPointerException.
Marquis de 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;}

Fonctionne bien sous Windows

Denton
la source
1

Ce qui est frustrant, c'est que lorsque vous développez dans Eclipse MyClass.class.getProtectionDomain().getCodeSource().getLocation()renvoie le /binrépertoire qui est génial, mais lorsque vous le compilez dans un bocal, le chemin inclut la /myjarname.jarpartie qui vous donne des noms de fichiers illégaux.

Pour que le code fonctionne à la fois dans l'idé et une fois qu'il est compilé dans un bocal, j'utilise le morceau de code suivant:

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");
}
Alexandre
la source
1

Pas vraiment sûr des autres, mais dans mon cas, cela ne fonctionnait pas avec un "pot exécutable" et je l'ai fait fonctionner en fixant les codes ensemble à partir de la réponse phchen2 et un autre à partir de ce lien: Comment obtenir le chemin d'un fichier JAR en cours d'exécution? Le code:

               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");
Fahad Alkamli
la source
1

J'ai essayé plusieurs des solutions là-haut, mais aucune n'a donné de résultats corrects dans le cas (probablement spécial) où le pot exécutable a été exporté avec "Empaqueter des bibliothèques externes" dans Eclipse. Pour une raison quelconque, toutes les solutions basées sur le ProtectionDomain aboutissent à null dans ce cas.

En combinant certaines solutions ci-dessus, j'ai réussi à obtenir le code de travail suivant:

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);
DragonGamer
la source
1

Essaye ça:

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

Cette méthode, appelée à partir du code dans l'archive, renvoie le dossier où se trouve le fichier .jar. Cela devrait fonctionner sous Windows ou 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);
  } 

Dérivé du code à: déterminer si l'exécution à partir de JAR

Bacup Lad
la source
3
"Il devrait fonctionner sous Windows ou Unix." mais échouera dans n'importe quelle applet et dans chaque application. lancé en utilisant JWS.
Andrew Thompson
0

Mentionnez qu'il est enregistré uniquement Windowsmais je pense que cela fonctionne parfaitement sur d'autres systèmes d'exploitation [ Linux,MacOs,Solaris] :).


J'avais 2 .jar fichiers dans le même répertoire. Je voulais à partir d'un .jarfichier pour démarrer l'autre .jarfichier qui se trouve dans le même répertoire.

Le problème est que lorsque vous le démarrez à partir du cmdrépertoire en cours, c'est system32.


Avertissements!

  • Ce qui suit semble fonctionner assez bien dans tous les tests que j'ai effectués même avec le nom du dossier ;][[;'57f2g34g87-8+9-09!2#@!$%^^&()ou ()%&$%^@# cela fonctionne bien.
  • J'utilise le ProcessBuilderavec le ci-dessous comme suit:

🍂 ..

//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;
    }
GOXR3PLUS
la source
0

Ce code a fonctionné pour moi:

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;
  }
John Lockwood
la source
0

Ce code a fonctionné pour moi pour identifier si le programme est exécuté dans un fichier JAR ou 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;
    }
}

Si j'ai besoin d'obtenir le chemin complet Windows du fichier JAR, j'utilise cette méthode:

    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;
        }
    }

Mon code complet fonctionnant avec une application Spring Boot utilisant l' CommandLineRunnerimplémentation, pour garantir que l'application soit toujours exécutée dans une vue console (Double-clique par erreur dans le nom du fichier JAR), j'utilise le code suivant:

@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;
        }
    }
}
Jairo Martínez
la source
-1

J'écris en Java 7 et teste sous Windows 7 avec le runtime d'Oracle et Ubuntu avec le runtime open source. Cela fonctionne parfaitement pour ces systèmes:

Le chemin d'accès au répertoire parent de tout fichier jar en cours d'exécution (en supposant que la classe appelant ce code est un enfant direct de l'archive jar elle-même):

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

Ainsi, le chemin de foo.jar serait:

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

Encore une fois, cela n'a été testé sur aucun Mac ou Windows plus ancien

sudoBen
la source
-1

L' getProtectionDomainapproche peut ne pas fonctionner parfois, par exemple lorsque vous devez trouver le fichier jar pour certaines des classes Java principales (par exemple, dans ma StringBuilderclasse de cas dans IBM JDK), cependant, la procédure suivante fonctionne de manière transparente:

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, "");
}
Vasu
la source
URL.getPath () ne fait pas ce que vous pensez qu'il fait. Tous les caractères spéciaux seront codés en pourcentage.
VGR
-1

J'ai une autre façon d'obtenir l'emplacement String d'une classe.

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

La chaîne de sortie aura la forme de

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

Les espaces et autres caractères sont traités, et sous la forme sans file:/. Ce sera donc plus facile à utiliser.

NoSegfault
la source