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 le foo en cours d'exécution.le pot est.
Donc, si foo.jar est dans C:FOO
, Je veux obtenir ce chemin quel que soit mon répertoire de travail actuel.
29 réponses
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.
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.
Pour obtenir File
pour un Class
, il y a deux étapes:
- convertissez le
Class
enURL
- convertissez le
URL
enFile
Il est important de comprendre les deux étapes et de ne pas les confondre.
Une Fois que vous avez la File
, vous pouvez appeler getParentFile
pour obtenir le dossier contenant, si c'est ce que vous avez besoin.
Étape 1: Class
à URL
Comme discuté dans d'autres réponses, il y a deux façons principales de trouver un URL
pertinent à un Class
.
URL url = Bar.class.getProtectionDomain().getCodeSource().getLocation();
URL url = Bar.class.getResource(Bar.class.getSimpleName() + ".class");
, les Deux ont des avantages et des inconvénients.
L'approche getProtectionDomain
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
lors de l'appel de getProtectionDomain()
, donc si votre application doit s'exécuter dans divers environnements, il est préférable de les tester dans tous.
L'approche getResource
donne le chemin de ressource URL complet de la classe, à partir de laquelle vous devrez effectuer une manipulation de chaîne supplémentaire. Il peut s'agir d'un chemin file:
, mais il peut 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 framework OSGi. Inversement, l'approche getProtectionDomain
donne correctement une URL file:
même à partir D'OSGi.
Notez que getResource("")
et getResource(".")
ont échoué dans mes tests, lorsque la classe résidait dans un fichier JAR; les deux invocations ont renvoyé null. Donc, je recommande l'invocation #2 montrée ci-dessus à la place, car elle semble plus sûr.
Étape 2: URL
à File
De toute façon, une fois que vous avez un URL
, l'étape suivante est de convertir en File
. C'est son propre défi; voir le billet de 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 découragerais fortement en utilisant URLDecoder
. Certains caractères de L'URL, :
et /
en particulier, ne sont pas des caractères codés par URL valides. À partir de la 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 échappée spéciale.
...
Il existe deux façons possibles pour ce décodeur de traiter les chaînes illégales. Il pourrait soit laisser des personnages illégaux seuls ou il pourrait jeter un IllegalArgumentException. L'approche adoptée par le décodeur est laissée à la mise en œuvre.
En pratique, URLDecoder
ne jette généralement pas {[35] } comme menacé ci-dessus. Et si votre chemin de fichier a des espaces codés comme %20
, cette approche peut sembler fonctionner. Cependant, si votre chemin de fichier contient d'autres caractères non alphamériques tels que +
, vous rencontrerez des problèmes avec URLDecoder
pour modifier votre chemin de fichier.
Code de travail
Pour réaliser ces étapes, vous pourriez avoir des méthodes comme ce qui suit:
/**
* 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 Commun bibliothèque:
Vous pouvez également utiliser:
CodeSource codeSource = YourMainClass.class.getProtectionDomain().getCodeSource();
File jarFile = new File(codeSource.getLocation().toURI().getPath());
String jarDir = jarFile.getParentFile().getPath();
Utiliser 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 est tiré de une question similaire .)
Pour trouver le répertoire, vous devez ensuite démonter l'URL manuellement. Voir le tutoriel JarClassLoader pour le format D'une URL jar.
Je suis surpris de voir qu'aucun récemment proposé d'utiliser Path
. Voici une citation: " la classe Path
comprend diverses méthodes qui peuvent ê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 est d'obtenir le Path
objeu comme:
Path path = Paths.get(Test.class.getProtectionDomain().getCodeSource().getLocation().toURI());
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();
}
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 j'ai été de l'aide pour vous.
Voici la mise à niveau vers d'autres commentaires, qui me semblent incomplets pour les détails de
En utilisant un "dossier" relatif à l'extérieur .fichier jar (dans le même fichier jar lieu):
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"));
La réponse sélectionnée ci-dessus ne fonctionne pas si vous exécutez votre jar en cliquant dessus à partir de L'environnement de bureau Gnome (pas à partir d'un script ou d'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 "";
}
Pour obtenir le chemin d'exécution du fichier jar, j'ai étudié les solutions ci-dessus et essayé toutes les méthodes qui existent entre elles. 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 c'est difficile, quand exécuter le fichier JAR exécutable directement ou via la ligne de commande, il sera échoué comme le chemin du fichier jar obtenu à partir des méthodes ci-dessus donnera un chemin interne dans le fichier jar, c'est qu'il donne toujours un chemin
Rsrc: project-name (peut - être devrais-je dire que c'est le nom du paquet du fichier de classe principal-la classe indiquée)
Je ne peux pas convertir le rsrc:... chemin vers un chemin externe, c'est-à-dire 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 de L'IDE Eclipse est
System.getProperty("java.class.path")
Cette ligne de code peut renvoie le chemin vivant (y compris le nom du fichier) du fichier JAR en cours d'exécution (notez que le chemin de retour n'est pas le répertoire de travail), comme le document java et certaines personnes ont dit qu'il renverra 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 jar en cours d'exécution (à propos du problème de plusieurs chemins en effet c'est arrivé dans L'Eclipse).
En fait, voici une meilleure version - l'ancienne a échoué si un nom de dossier avait un espace dedans.
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);
}
En ce qui concerne l'échec avec les applets, vous n'auriez généralement pas accès aux fichiers locaux de toute façon. Je ne sais pas grand - chose sur JWS mais pour gérer les fichiers locaux pourrait-il ne pas être possible de télécharger l'application.?
String path = getClass().getResource("").getPath();
Le chemin fait toujours référence à la ressource dans le fichier jar.
La solution la plus simple consiste à passer le chemin en argument lors de l'exécution du jar.
Vous pouvez automatiser cela avec un script shell (.bat dans Windows,. sh nulle part ailleurs):
java -jar my-jar.jar .
J'ai utilisé .
pour passer le répertoire de travail actuel.
Mise à JOUR
Vous pouvez 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 une bonne erreur message si les arguments sont manquants.
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.
Utiliser
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile();
J'ai dû faire beaucoup de bêtises avant de finalement trouver une solution de travail (et courte).
Il est possible que le jarLocation
soit livré avec un préfixe comme file:\
ou jar:file\
, qui peut être supprimé en utilisant String#substring()
.
URL jarLocationUrl = MyClass.class.getProtectionDomain().getCodeSource().getLocation();
String jarLocation = new File(jarLocationUrl.toString()).getParent();
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 sur Windows
J'ai essayé d'obtenir le chemin d'exécution du pot en utilisant
String folder = MyClassName.class.getProtectionDomain().getCodeSource().getLocation().getPath();
c:\app > application java-jar.jar
Exécution de l'application jar nommée " application.jar", sous Windows, dans le dossier "c:\app, la valeur de la variable de Chaîne "dossier" a "\c:\app\application.jar " et j'ai eu des problèmes pour tester l'exactitude 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 bon format comme " c:\app " au lieu de "\c:\app\application.jar " et j'ai remarqué que ça marchait.
Quelque chose qui est frustrant, c'est que lorsque vous développez dans Eclipse MyClass.class.getProtectionDomain().getCodeSource().getLocation()
renvoie le répertoire /bin
qui est génial, mais lorsque vous le compilez dans un jar, le chemin inclut la partie /myjarname.jar
qui vous donne des noms de fichiers illégaux.
Pour que le code fonctionne à la fois dans l'ide et une fois compilé dans un jar, j'utilise le 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");
}
Pas vraiment sûr des autres mais dans mon cas cela n'a pas fonctionné avec un "jar Runnable" et je l'ai fait fonctionner en fixant des codes ensemble à partir de la réponse phchen2 et un autre 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");
Cette méthode, appelée à partir du code dans l'archive, renvoie le dossier où le.le fichier jar est. 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é de code: Déterminer si l'exécution de JAR
Mentionner qu'il n'est vérifiée que dans Windows
, mais je pense qu'il fonctionne parfaitement sur d'autres Systèmes d'Exploitation [Linux,MacOs,Solaris
] :).
, j'ai eu 2 .jar
les fichiers dans le même répertoire . Je voulais partir d'un fichier .jar
pour démarrer l'autre fichier .jar
qui se trouve dans le même répertoire.
Le problème est que lorsque vous le démarrez à partir de la cmd
, le répertoire courant est system32
.
Avertissements!
- le ci-dessous semble fonctionner assez Eh bien dans tous les tests que j'ai fait même
avec le nom du dossier
;][[;'57f2g34g87-8+9-09!2#@!$%^^&()
ou()%&$%^@#
il fonctionne bien. - j'utilise le
ProcessBuilder
avec 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;
}
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;
}
Ignorer la réponse de lad de sauvegarde, cela peut sembler correct parfois mais a plusieurs problèmes:
Ici, les deux devraient être +1 pas -1:
name = name.substring(name.lastIndexOf(':')-1, name.lastIndexOf('/')+1).replace('%', ' ');
Très dangereux car n'est pas immédiatement évident si le chemin n'a pas d'espaces blancs, mais le remplacement juste Du " % " vous laissera avec un tas de 20 dans chaque espace blanc:
name = name.substring(name.lastIndexOf(':')-1, name.lastIndexOf('/')+1).replace('%', ' ');
Il y a de meilleurs moyens que cette boucle pour les espaces blancs.
En outre, il causera des problèmes au moment du débogage.
J'écris en Java 7, et je teste dans Windows 7 avec le runtime D'Oracle, et Ubuntu avec le runtime open source. Cela fonctionne parfaitement pour ces systèmes:
Le chemin du 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
Donc, le chemin de foo.jar serait:
fooPath = fooDirPath + File.separator + "foo.jar";
Encore une fois, cela n'a pas été testé sur un Mac ou Windows Plus
L'approche getProtectionDomain
peut parfois ne pas fonctionner, par exemple lorsque vous devez trouver le jar pour certaines des classes java de base (par exemple, dans mon cas, la classe StringBuilder
dans IBM JDK), mais la suite 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, "");
}
J'ai un autre moyen d'obtenir L'emplacement de la chaîne d'une classe.
URL path = Thread.currentThread().getContextClassLoader().getResource("");
Path p = Paths.get(path.toURI());
String location = p.toString();
La Chaîne de sortie sera de la forme de
C:\Users\Administrator\new Workspace\...
Les espaces et autres caractères sont gérés, et sous la forme sans file:/
. Ce sera plus facile à utiliser.
Ou vous pouvez passer le Thread courant comme ceci:
String myPath = Thread.currentThread().getContextClassLoader().getResource("filename").getPath();
Ce paquebot fonctionne pour les dossiers contenant des espaces ou des caractères spéciaux (comme ç ou∞). La question originale demande le chemin absolu (répertoire de travail), sans le fichier JAR lui-même. Testé ici avec Java7 sur Windows7:
String workingDir = System.getProperty("user.dir");
Référence: http://www.mkyong.com/java/how-to-get-the-current-working-directory-in-java/