¿Cómo obtener la ruta de un archivo JAR en ejecución?


580

Mi código se ejecuta dentro de un archivo JAR, digamos foo.jar , y necesito saber, en el código, en qué carpeta se ejecuta foo.jar encuentra .

Entonces, si foo.jar está dentro C:\FOO\, quiero obtener esa ruta sin importar cuál sea mi directorio de trabajo actual.


Vea la respuesta de Fab para una solución que funciona cuando las rutas incluyen espacios. Además, tenga en cuenta que algunas respuestas a continuación abordan la pregunta en el título (ruta jar), algunas abordan la pregunta en sí (ruta de la carpeta que contiene jar) y algunas proporcionan rutas a las clases dentro del archivo jar.
Andy Thomas

32
¡Cuidado al usar en ANT! ============== Llamo a String path = SomeClass.class.getProtectionDomain (). GetCodeSource (). GetLocation (). GetPath (); y obtener: /C:/apache-ant-1.7.1/lib/ant.jar ¡No es muy útil!
Dino Fancellu

Interesante. El código original en el que usé esto nunca se ejecutó en hormiga, por lo que no es un problema para mí.
Thiago Chaves

2
@Dino Fancellu, experimenté exactamente lo que describiste. Funciona durante el desarrollo, falla cuando se construye en jar.
Amigo

Respuestas:


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

Reemplace "MyClass" con el nombre de su clase.

Obviamente, esto hará cosas extrañas si su clase se cargó desde una ubicación que no es de archivo.


43
El toURI()paso es vital para evitar problemas con caracteres especiales, incluidos espacios y ventajas. La línea correcta es: El return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI()); uso URLDecoderno funciona para muchos caracteres especiales. Vea mi respuesta a continuación para más detalles.
ctrueden

44
Nota: esto devuelve la ruta que incluye el nombre del archivo jar
Buddy

8
¿Esto no apunta al archivo jar, en lugar del directorio en ejecución? Tendrá que hacer un getParentFile () en el resultado para este trabajo.
FOO

1
Además, getProtectionDomaines nulo si está obteniendo su clase de una pista de seguimiento:val strace = Thread.currentThread().getStackTrace; val path = strace(1).getClass.getProtectionDomain
bbarker

1
Usando este método con hasta Java 8; colocando este método en una clase que está en un Jar externo, cargado a través de class-path, luego se dará la ruta del jar externo en lugar del Jar real en ejecución.
Mr00Anderson

189

La mejor solución para mí:

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

Esto debería resolver el problema con espacios y caracteres especiales.


8
Una nota más: al llamar a esta función desde el Jar, el nombre del jar se agrega al final para mí, por lo tanto, tuve que ejecutar: path.substring (0, path.lastIndexOf ("/") + 1);
will824

11
/ no es necesariamente el separador de ruta. Debería hacer (nuevo archivo (ruta)). GetParentFile (). GetPath () en su lugar.
pjz

10
No hay problemas con el nombre del archivo JAR que se agrega aquí. La conversión UTF parece ser la solución perfecta en combinación con @Iviggiani one's ( URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");) en Linux. Sin embargo, no probé en Windows.
ubuntudroid

2
Gracias, esto me permitió cargar archivos externos a mi JAR con FileInputStream en Linux y Windows. Solo tenía que agregar la ruta decodificada delante del nombre del archivo ...
giorgio79

11
Cuidado: no se recomienda usar URLDecoderpara decodificar caracteres especiales. En particular, los caracteres como +se decodificarán erróneamente en espacios. Vea mi respuesta para más detalles.
ctrueden

153

Para obtener el Filepara un dado Class, hay dos pasos:

  1. Convertir el ClassaURL
  2. Convierte el URLaFile

Es importante comprender ambos pasos y no combinarlos.

Una vez que tenga el File, puede llamargetParentFile para obtener la carpeta que lo contiene, si eso es lo que necesita.

Paso 1: ClassaURL

Como se discutió en otras respuestas, hay dos formas principales de encontrar una URLrelevante para a Class.

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

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

Ambos tienen pros y contras.

El getProtectionDomainenfoque produce la ubicación base de la clase (por ejemplo, el archivo JAR que contiene). Sin embargo, es posible que la política de seguridad del tiempo de ejecución de Java se ejecute SecurityExceptional llamar getProtectionDomain(), por lo que si su aplicación necesita ejecutarse en una variedad de entornos, lo mejor es probar en todos ellos.

El getResourceenfoque produce la ruta de recursos de URL completa de la clase, desde la cual deberá realizar una manipulación de cadena adicional. Puede ser un file:camino, pero también podría ser jar:file:o incluso algo más desagradable bundleresource://346.fwk2106232034:4/foo/Bar.classcuando se ejecuta dentro de un marco OSGi. Por el contrario, el getProtectionDomainenfoque produce correctamente unfile: URL incluso desde OSGi.

Tenga en cuenta que tanto getResource("")y getResource(".")fallaron en mis pruebas, cuando la clase residía dentro de un archivo JAR; ambas invocaciones volvieron nulas. Por lo tanto, recomiendo la invocación n. ° 2 que se muestra arriba, ya que parece más segura.

Paso 2: URL aFile

De cualquier manera, una vez que tenga un URL, el siguiente paso es convertirlo en a File. Este es su propio desafío; vea la publicación del blog de Kohsuke Kawaguchi al respecto para obtener detalles completos, pero en resumen, puede usarnew File(url.toURI()) siempre que la URL esté completamente bien formada.

Por último, desalentaría mucho el uso URLDecoder. Algunos caracteres de la URL, :y /en particular, no son caracteres válidos codificados con URL. Desde el Javadoc URLDecoder :

Se supone que todos los caracteres en la cadena codificada son uno de los siguientes: "a" a "z", "A" a "Z", "0" a "9" y "-", "_", " . "y" * ". El carácter "%" está permitido pero se interpreta como el inicio de una secuencia especial de escape.

...

Hay dos formas posibles en que este decodificador puede manejar cadenas ilegales. Podría dejar solo caracteres ilegales o podría generar una IllegalArgumentException. El enfoque que tome el decodificador se deja a la implementación.

En la práctica, URLDecodergeneralmente no arroja IllegalArgumentExceptioncomo se amenaza anteriormente. Y si su ruta de archivo tiene espacios codificados como %20, este enfoque puede parecer que funciona. Sin embargo, si la ruta de su archivo tiene otros caracteres no alfabéticos, como por ejemplo +, tendrá problemas para URLDecodercambiar la ruta de su archivo.

Código de trabajo

Para lograr estos pasos, puede tener métodos como los siguientes:

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

Puede encontrar estos métodos en la biblioteca SciJava Common :


55
+1; la mejor respuesta hasta la fecha: devolverá la ruta utilizando la notación correcta para el sistema operativo. (por ejemplo, \ para windows).
Betsabé

Con respecto a la seguridad, creo que descubrí que Java WebStart no lo permitía.
Thorbjørn Ravn Andersen

55

También puedes usar:

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

3
¡Esto funciona mejor para mí, porque da el camino del Jar, no de la clase!
T30

A mí también me funcionó. ¡Combínalo con la respuesta de Fab y mejorará!
Danielson Alves Júnior

25

Use ClassLoader.getResource () para encontrar la URL de su clase actual.

Por ejemplo:

package foo;

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

(Este ejemplo está tomado de una pregunta similar ).

Para encontrar el directorio, deberá desarmar la URL manualmente. Consulte el tutorial JarClassLoader para ver el formato de una URL jar.


Mi archivo JAR está ofuscado, por lo que esta respuesta no resuelve mi problema. Pero no he especificado eso en la pregunta, por lo que esta sigue siendo una respuesta válida.
Thiago Chaves

12
Si está ofuscado, use Test.class.getName () y realice el munging apropiado.
Jon Skeet

1
@ JonSkeet hay tantos problemas con su respuesta: 1. No habrá NPEporque no respondió a la pregunta que se le hizo (se le preguntó la ruta al directorio JAR y respondió a una pregunta absolutamente diferente: ruta a la clase). 2. Como señalaron otros, y obtuve el mismo problema, no funciona para los applets. 3. camino de retorno no sea de la representación ruta canónica en absoluto: jar:file:/listener/build/libs/listener-1.0.0-all.jar!/shared/Test.class.
WhiteAngel

1
@WhiteAngel: 1) La última línea de mi publicación indica que deberías mirar la URL y separarla para obtener el archivo jar. Estoy de acuerdo en que no es la respuesta más completa, pero no creo que sea realmente tan malo que valga la pena discutir (especialmente 10 años después ...) 2) Los applets no se mencionaron en ningún comentario aquí ; curiosamente, no No tengo tiempo para mirar todos los comentarios sobre todas las respuestas a las preguntas a las que les publiqué una respuesta. 3) Nuevamente, enlace al formato de la URL del jar.
Jon Skeet

2
@WhiteAngel: ¿Es la mejor respuesta que he escrito? No ¿Es tan malo como pretendes que sea? No, no lo creo. (Particularmente en términos de las afirmaciones que hizo a su alrededor arrojando un NPE, lo que no hace). Le sugeriría que agregue su propia respuesta en lugar de hacer un escándalo sobre esta. Ese sería un enfoque más positivo.
Jon Skeet

19

Me sorprende ver que ninguno recientemente propuso su uso Path. Aquí sigue una cita: " La Pathclase incluye varios métodos que pueden usarse para obtener información sobre la ruta, acceder a elementos de la ruta, convertir la ruta a otras formas o extraer partes de una ruta "

Por lo tanto, una buena alternativa es obtener el Pathobjest como:

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

3
Como nota, Path está disponible a partir de Java 7.
Chris Forrence

15

La única solución que funciona para mí en Linux, Mac y 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();
}

Esto no funcionará. Si en Linux, el método toUri () arrojará una excepción, y no llegará a la parte else, para linux.
Wilhelm Sorban

9

Tuve el mismo problema y lo resolví de esa manera:

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

Espero haberte sido de ayuda.


No hagas eso. URL.getPath () no devuelve un nombre de archivo y fallará en muchas circunstancias, como rutas de archivos con espacios en ellas.
VGR

9

Aquí hay una actualización a otros comentarios, que me parecen incompletos para los detalles de

usando una "carpeta" relativa fuera del archivo .jar (en la misma ubicación del 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"));

44
Cuidado: no se recomienda usar URLDecoderpara decodificar caracteres especiales. En particular, los caracteres como +se decodificarán erróneamente en espacios. Vea mi respuesta para más detalles.
ctrueden

No se recomienda el uso de caracteres especiales en los nombres de archivo.
Zon

URLDecoder, a pesar de su nombre, es para decodificar URL y formar nombres y valores de parámetros, no URL.
Marqués de Lorne

6

Para obtener la ruta de ejecución del archivo jar, he estudiado las soluciones anteriores y probado todos los métodos que existen alguna diferencia entre sí. Si estos códigos se ejecutan en Eclipse IDE, todos deberían poder encontrar la ruta del archivo, incluida la clase indicada, y abrir o crear un archivo indicado con la ruta encontrada.

Pero es complicado, cuando ejecuta el archivo jar ejecutable directamente o a través de la línea de comando, fallará ya que la ruta del archivo jar obtenida de los métodos anteriores dará una ruta interna en el archivo jar, es decir, siempre da una ruta como

rsrc: nombre-proyecto (tal vez debería decir que es el nombre del paquete del archivo de clase principal - la clase indicada)

No puedo convertir la ruta rsrc: ... a una ruta externa, es decir, cuando ejecuta el archivo jar fuera del IDE de Eclipse, no puede obtener la ruta del archivo jar.

La única forma posible de obtener la ruta de ejecución del archivo jar fuera de Eclipse IDE es

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

esta línea de código puede devolver la ruta viva (incluido el nombre del archivo) del archivo jar en ejecución (tenga en cuenta que la ruta de retorno no es el directorio de trabajo), como el documento de Java y algunas personas dijeron que devolverá las rutas de todos los archivos de clase en el mismo directorio, pero como mis pruebas si en el mismo directorio incluyen muchos archivos jar, solo devuelve la ruta de ejecución de jar (sobre el problema de las rutas múltiples, de hecho, sucedió en Eclipse).


java.class.pathPuede ser multivalor. Uno de esos valores ciertamente proporcionará el directorio o el archivo JAR donde se encuentra la clase actual, pero ¿cuál?
Marqués de Lorne

Confirmo que probé otras soluciones, pero nunca recibí el nombre del archivo jar. Esto funciona de manera muy simple! gracias - +1
guillaume girod-vitouchkina

5

Otras respuestas parecen apuntar a la fuente del código que es la ubicación del archivo Jar que no es un directorio.

Utilizar

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

Puede ser un directorio, si está cargando sus clases desde un sistema de archivos en lugar de un archivo JAR, por ejemplo, al depurar.
Marqués de Lorne

4

la respuesta seleccionada arriba no funciona si ejecuta su jar haciendo clic en él desde el entorno de escritorio Gnome (no desde cualquier script o terminal).

En cambio, me gusta que la siguiente solución esté funcionando en todas partes:

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

2
¿Intentó eso en un applet o una aplicación? lanzado con Java Web Start? Tengo entendido que fallará en ambas situaciones (incluso si la aplicación es confiable).
Andrew Thompson

Esta solución solo puede devolver la ubicación de "." dentro del archivo JAR, no la ubicación del archivo JAR.
Marqués de Lorne

Cuidado: no se recomienda usar URLDecoderpara decodificar caracteres especiales. En particular, los caracteres como +se decodificarán erróneamente en espacios. Vea mi respuesta para más detalles.
ctrueden

En el arranque de primavera, lanzaráNullPointerException
Ravi Parekh

Tendrá NPEsi no hay recursos en JAR.
WhiteAngel

3

En realidad, aquí hay una versión mejor: la anterior fallaba si el nombre de una carpeta tenía un espacio.

  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 cuanto a fallar con los applets, de todos modos no tendrías acceso a los archivos locales. No sé mucho sobre JWS, pero para manejar archivos locales, ¿no podría ser posible descargar la aplicación?


Hay varias formas integradas para decodificar el camino. No es necesario que escriba su propio código.
Marqués de Lorne

3

Traté de obtener la ruta de ejecución de jar usando

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

c: \ app> java -jar application.jar

Al ejecutar la aplicación jar denominada "application.jar", en Windows en la carpeta " c: \ app ", el valor de la variable de cadena "carpeta" era " \ c: \ app \ application.jar " y tuve problemas para probar la corrección del camino

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

Así que traté de definir "prueba" como:

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

para obtener la ruta en un formato correcto como " c: \ app " en lugar de " \ c: \ app \ application.jar " y noté que funciona.


3

La solución más simple es pasar la ruta como argumento al ejecutar el jar.

Puede automatizar esto con un script de shell (.bat en Windows, .sh en cualquier otro lugar):

java -jar my-jar.jar .

Solía .pasar el directorio de trabajo actual.

ACTUALIZAR

Es posible que desee pegar el archivo jar en un subdirectorio para que los usuarios no hagan clic accidentalmente en él. Su código también debe verificar para asegurarse de que se hayan proporcionado los argumentos de la línea de comandos y proporcionar un buen mensaje de error si faltan los argumentos.


3

Tuve que perder el tiempo mucho antes de finalmente encontrar una solución funcional (y corta).
Es posible que jarLocationvenga con un prefijo como file:\o jar:file\, que se puede eliminar mediante el uso String#substring().

URL jarLocationUrl = MyClass.class.getProtectionDomain().getCodeSource().getLocation();
String jarLocation = new File(jarLocationUrl.toString()).getParent();

2
String path = getClass().getResource("").getPath();

La ruta siempre se refiere al recurso dentro del archivo jar.


1
Esa cadena de ruta aún debe simplificarse según sus necesidades. String path = new File(getClass().getResource("").getPath()).getParentFile().getParent(); File jarDir = new File(path.substring(5));
ZZZ

44
Ambos getResource("")y getResource(".")fallaron en mis pruebas, cuando la clase residía dentro de un archivo JAR; ambas invocaciones volvieron nulas.
ctrueden

2
Esto arroja NullPointerException.
Marqués 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;}

Funciona bien en Windows


1

Algo que es frustrante es que cuando está desarrollando en Eclipse MyClass.class.getProtectionDomain().getCodeSource().getLocation()devuelve el /bindirectorio que es excelente, pero cuando lo compila en un jar, la ruta incluye la /myjarname.jarparte que le da nombres de archivo ilegales.

Para que el código funcione tanto en el ide como una vez que se compila en un jar, utilizo el siguiente fragmento de código:

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

1

No estoy realmente seguro acerca de los demás, pero en mi caso no funcionó con un "Jar ejecutable" y lo puse a trabajar arreglando los códigos de la respuesta phchen2 y otro de este enlace: ¿Cómo obtener la ruta de un archivo JAR en ejecución? El código:

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

1

He intentado varias de las soluciones allí, pero ninguna arrojó resultados correctos para el caso (probablemente especial) de que el jar ejecutable se ha exportado con "Empaquetar bibliotecas externas" en Eclipse. Por alguna razón, todas las soluciones basadas en el ProtectionDomain resultan nulas en ese caso.

Al combinar algunas de las soluciones anteriores, logré lograr el siguiente código de trabajo:

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

1

Prueba esto:

String path = new File("").getAbsolutePath();

0

Este método, llamado desde el código en el archivo, devuelve la carpeta donde está el archivo .jar. Debería funcionar en Windows o 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);
  } 

Derivado del código en: Determinar si se ejecuta desde JAR


3
"Debería funcionar en Windows o Unix". pero fallará en cualquier applet y en cada aplicación. lanzado usando JWS.
Andrew Thompson

0

Mencione que solo está registrado Windowspero creo que funciona perfectamente en otros sistemas operativos [ Linux,MacOs,Solaris] :).


Tenía 2 .jar archivos en el mismo directorio. Quería que desde un .jararchivo comenzara el otro .jararchivo que está en el mismo directorio.

El problema es que cuando lo inicia desde el cmddirectorio actual es system32.


Advertencias!

  • Lo siguiente parece funcionar bastante bien en todas las pruebas que he hecho incluso con el nombre de la carpeta ;][[;'57f2g34g87-8+9-09!2#@!$%^^&()o()%&$%^@# funciona bien.
  • Estoy usando ProcessBuilderel siguiente de la siguiente manera:

🍂 ..

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

0

Este código funcionó para mí:

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

0

Este código me funcionó para identificar si el programa se está ejecutando dentro de un archivo JAR o 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 necesito obtener la ruta completa de Windows del archivo JAR, estoy usando este método:

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

Mi código completo trabajando con una aplicación Spring Boot usando la CommandLineRunnerimplementación, para asegurar que la aplicación siempre se ejecute dentro de una vista de consola (Doble clic por error en el nombre del archivo JAR), estoy usando el siguiente código:

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

-1

Escribo en Java 7 y pruebo en Windows 7 con el tiempo de ejecución de Oracle y Ubuntu con el tiempo de ejecución de código abierto. Esto funciona perfecto para esos sistemas:

La ruta para el directorio padre de cualquier archivo jar en ejecución (suponiendo que la clase que llama a este código es un hijo directo del archivo jar):

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

Entonces, el camino de foo.jar sería:

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

Nuevamente, esto no fue probado en ninguna Mac o Windows anterior


-1

El getProtectionDomainenfoque puede no funcionar a veces, por ejemplo, cuando tiene que encontrar el jar para algunas de las clases principales de Java (por ejemplo, en mi StringBuilderclase de caso dentro de IBM JDK), sin embargo, lo siguiente funciona a la perfección:

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

URL.getPath () no hace lo que crees que hace. Cualquier carácter especial estará codificado en porcentaje.
VGR

-1

Tengo otra forma de obtener la ubicación de String de una clase.

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

La cadena de salida tendrá la forma de

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

Los espacios y otros caracteres se manejan, y en la forma sin file:/. Entonces será más fácil de usar.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.