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 le fichier foo.jar en cours d'exécution.
Donc, si foo.jar est dans C:\FOO\
, je veux obtenir ce chemin, quel que soit mon répertoire de travail actuel.
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 depuis un emplacement autre que le 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 des espaces et des caractères spéciaux.
Pour obtenir le File
pour un Class
donné, il y a deux étapes:
Class
en un URL
URL
en un File
Il est important de comprendre les deux étapes et de ne pas les mélanger.
Une fois que vous avez le File
, vous pouvez appeler getParentFile
pour obtenir le dossier contenant, si c'est ce dont vous avez besoin.
Class
à URL
Comme indiqué dans d'autres réponses, il existe deux méthodes principales pour trouver une URL
pertinente à une 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 politique de sécurité du runtime Java jette SecurityException
lors de l'appel de getProtectionDomain()
. Par conséquent, si votre application doit s'exécuter dans plusieurs environnements, il est préférable de les tester dans chacun d'entre eux. .
L'approche getResource
donne le chemin de ressource d'URL complet de la classe, à partir duquel vous devrez effectuer une manipulation de chaîne supplémentaire. Il peut s'agir d'un chemin file:
, mais il peut également s'agir de jar:file:
ou même de quelque chose de plus méchant comme bundleresource://346.fwk2106232034:4/foo/Bar.class
lors de l'exécution dans un cadre OSGi. Inversement, l'approche getProtectionDomain
génère correctement une URL file:
même à partir de OSGi.
Notez que getResource("")
et getResource(".")
ont échoué lors de 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 cela semble plus sûr.
URL
à File
Quoi qu'il en soit, une fois que vous avez un URL
, l'étape suivante consiste à convertir en un 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 formée.
Enfin, je découragerais fortement d'utiliser URLDecoder
. Certains caractères de l'URL, :
et /
en particulier, ne sont pas des caractères valides codés par URL. Depuis le RLDecoder 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.
...
Ce décodeur peut traiter les chaînes illégales de deux manières. Cela peut laisser les caractères illégaux ou lancer une exception IllegalArgumentException. L'approche prise par le 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 contient des espaces codés comme %20
, cette approche peut sembler fonctionner. Toutefois, si votre chemin de fichier comporte d'autres caractères non alphanétiques, tels que +
, vous aurez des problèmes avec URLDecoder
en modifiant votre chemin.
Pour réaliser ces étapes, vous pouvez utiliser des méthodes telles que:
/**
* 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 SciJava Common :
Vous pouvez aussi utiliser:
CodeSource codeSource = YourMainClass.class.getProtectionDomain().getCodeSource();
File jarFile = new File(codeSource.getLocation().toURI().getPath());
String jarDir = jarFile.getParentFile().getPath();
Utilisez ClassLoader.getResource () pour rechercher 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 ne question similaire .)
Pour trouver le répertoire, vous devez ensuite séparer l'URL manuellement. Consultez le tutoriel JarClassLoader pour connaître le format d'une URL jar.
Je suis surpris de voir qu’aucun d’entre eux n’a récemment proposé d’utiliser Path
. Voici une citation: " La classe Path
comprend diverses méthodes permettant d’obtenir des informations sur le chemin, d’accéder aux éléments du chemin, de convertir le chemin en autres formulaires ou d’extraire des parties d’un fichier. chemin "
Ainsi, une bonne alternative consiste à obtenir l'object Path
sous la forme:
Path path = Paths.get(Test.class.getProtectionDomain().getCodeSource().getLocation().toURI());
La seule solution qui fonctionne pour moi sous 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();
}
Voici la mise à niveau vers d’autres commentaires, qui me paraissent incomplets pour les spécificités de
en utilisant un "dossier" relatif en dehors du fichier .jar (au même emplacement du 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"));
J'ai eu le même problème et je l'ai résolu ainsi:
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 vous ai aidé.
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 qui diffèrent les unes des autres. Si ces codes sont exécutés dans Eclipse IDE, ils doivent tous être en mesure de trouver le chemin du fichier, y compris la classe indiquée, et d'ouvrir ou de créer un fichier avec le chemin trouvé.
Mais c’est délicat, lorsqu’il est exécuté directement ou par l’intermédiaire de la ligne de commande, lorsqu’il exécute le fichier jar exécutable, le chemin du fichier jar obtenu à partir des méthodes ci-dessus donnera un chemin interne au fichier jar, c’est-à-dire qu’il donne toujours un chemin. comme
rsrc: nom-projet (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 chemin rsrc: ... en un chemin externe, c’est-à-dire lorsqu’il exécute le fichier jar en dehors de Eclipse IDE, 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 d’Eclipse IDE est
System.getProperty("Java.class.path")
cette ligne de code peut renvoyer le chemin d'accès 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 que certaines personnes ont dit qu'il renverrait les chemins de tous les fichiers de classe dans le même répertoire, mais comme mes tests dans le même répertoire incluent de nombreux fichiers jar, il ne renvoie que le chemin d’exécution de jar (à propos du problème des chemins multiples, en effet il s’est passé dans Eclipse).
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();
la réponse sélectionnée ci-dessus ne fonctionne pas si vous exécutez votre fichier jar en cliquant dessus depuis l'environnement de bureau Gnome (et non depuis un script ou un terminal).
Au lieu de cela, j’ai trouvé que la solution suivante fonctionne partout:
try {
return URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");
} catch (UnsupportedEncodingException e) {
return "";
}
La solution la plus simple consiste à passer le chemin en tant qu'argument lors de l'exécution du fichier jar.
Vous pouvez automatiser cela avec un script Shell (.bat dans Windows, .sh ailleurs):
Java -jar my-jar.jar .
J'ai utilisé .
pour transmettre le répertoire de travail actuel.
UPDATE
Vous voudrez peut-être coller le fichier jar dans un sous-répertoire afin que les utilisateurs ne cliquent pas dessus accidentellement. Votre code doit également vérifier que les arguments de la ligne de commande ont bien été fournis et fournir un bon message d'erreur si les arguments sont manquants.
J'ai dû beaucoup déconner avant de finalement trouver une solution efficace (et courte).
Il est possible que la jarLocation
soit fournie avec un préfixe tel que 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();
En fait, voici une meilleure version - l'ancienne version échouait 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);
}
En ce qui concerne les échecs avec les applets, vous n’auriez de toute façon pas accès aux fichiers locaux. Je ne connais pas grand chose à JWS, mais il pourrait ne pas être possible de télécharger l'application pour gérer les fichiers locaux.?
String path = getClass().getResource("").getPath();
Le chemin fait toujours référence à la ressource dans le fichier jar.
J'ai essayé d'obtenir le chemin d'accès au 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 "dossier" était "\ 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 d'accès dans un format correct comme "c:\app" au lieu de "\ c:\app\application.jar" et j'ai remarqué que cela fonctionnait.
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
Je ne suis pas vraiment sûr des autres, mais dans mon cas, cela ne fonctionnait pas avec un "pot exécutable" et je l'ai obtenu en corrigeant ensemble les codes de phchen2 answer et un autre à partir de ce lien: Comment obtenir le chemin d'un Lancer le fichier JAR? 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");
Ce qui est frustrant, c’est que lorsque vous développez dans Eclipse, MyClass.class.getProtectionDomain().getCodeSource().getLocation()
renvoie le répertoire /bin
, ce qui est très bien, mais lorsque vous le compilez dans un fichier jar, le chemin contient la partie /myjarname.jar
qui donne vous noms de fichiers illégaux.
Pour que le code fonctionne à la fois dans l'ide et une fois qu'il est compilé dans un fichier 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");
}
J'ai essayé plusieurs solutions, mais aucune n'a donné de résultats corrects dans le cas (probablement spécial) du fait que le fichier jar exécutable a été exporté avec "Packaging external libraries" dans Eclipse. Pour une raison quelconque, toutes les solutions basées sur ProtectionDomain donnent la valeur null dans ce cas.
En combinant certaines des 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);
Cette méthode, appelée à partir du code de l’archive, renvoie le dossier dans lequel 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 du fichier JAR
Essaye ça:
String path = new File("").getAbsolutePath();
Mentionnez qu'il est vérifié seulement dans Windows
mais je pense que cela fonctionne parfaitement sur d'autres systèmes d'exploitation [Linux,MacOs,Solaris
]:).
J'ai eu 2.jar
fichiers dans le même répertoire. Je voulais que le fichier .jar
démarre 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 cmd
, le répertoire actuel est system32
.
Avertissements!
;][[;'57f2g34g87-8+9-09!2#@!$%^^&()
ou ()%&$%^@#
cela fonctionne bien.ProcessBuilder
avec 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;
}