Come ottenere il percorso di un file JAR in esecuzione?


580

Il mio codice viene eseguito all'interno di un file JAR, ad esempio foo.jar , e devo sapere, nel codice, in quale cartella il foo.jar in esecuzione .

Quindi, se foo.jar è in C:\FOO\, voglio ottenere quel percorso indipendentemente dalla mia attuale directory di lavoro.


Vedi la risposta di Fab per una soluzione che funziona quando i percorsi includono spazi. Inoltre, si noti che alcune risposte di seguito affrontano la domanda nel titolo (percorso jar), alcune rispondono alla domanda stessa (percorso della cartella contenente jar) e alcune forniscono percorsi alle classi all'interno del file jar.
Andy Thomas,

32
Attenzione quando si utilizza in ANT! ============== Chiamo String path = SomeClass.class.getProtectionDomain (). GetCodeSource (). GetLocation (). GetPath (); e ottieni: /C:/apache-ant-1.7.1/lib/ant.jar Non molto utile!
Dino Fancellu,

Interessante. Il codice originale in cui l'ho usato non è mai stato eseguito in ant, quindi non è un problema per me.
Thiago Chaves,

2
@Dino Fancellu, ho sperimentato esattamente quello che hai descritto. Funziona durante lo sviluppo, non riesce quando costruito per jar.
Buddy,

Risposte:


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

Sostituisci "MyClass" con il nome della tua classe.

Ovviamente, questo farà cose strane se la tua classe è stata caricata da un percorso non di file.


43
Il toURI()passaggio è fondamentale per evitare problemi con caratteri speciali, inclusi spazi e vantaggi. La riga corretta corretta è: L' return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI()); uso URLDecodernon funziona per molti caratteri speciali. Vedi la mia risposta di seguito per ulteriori dettagli.
ctrueden,

4
Nota: questo restituisce il percorso incluso il nome del file jar
Buddy

8
Questo non punta al file jar, anziché alla directory in esecuzione? Dovrai fare un risultato getParentFile () per questo lavoro.
FOO,

1
Inoltre, getProtectionDomainè nullo se stai ottenendo la tua lezione da uno stracktrace:val strace = Thread.currentThread().getStackTrace; val path = strace(1).getClass.getProtectionDomain
bbarker

1
Utilizzando questo metodo con fino a Java 8; posizionando questo metodo in una classe che si trova in un Jar esterno, caricato tramite class-path, verrà fornito il percorso del Jar esterno invece del Jar in esecuzione effettivo.
Mr00Anderson,

189

La migliore soluzione per me:

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

Questo dovrebbe risolvere il problema con spazi e caratteri speciali.


8
Un'altra nota: mentre chiami questa funzione dal Jar, il nome del jar viene aggiunto alla fine per me, quindi ho dovuto eseguire: path.substring (0, path.lastIndexOf ("/") + 1);
will824,

11
/ non è necessariamente il separatore di percorso. Dovresti invece fare (nuovo File (percorso)). GetParentFile (). GetPath ().
pjz,

10
Nessun problema con il nome del file JAR aggiunto qui. La conversione UTF sembra essere la soluzione perfetta in combinazione con @Iviggiani (( URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");) su Linux. Tuttavia, non ho provato su Windows.
ubuntudroid,

2
Grazie, questo mi ha permesso di caricare file esterni al mio JAR con FileInputStream sia in Linux che in Windows. Ho dovuto solo aggiungere il percorso decodificato davanti al nome del file ...
giorgio79,

11
Attenzione: non è consigliabile utilizzare URLDecoderper decodificare caratteri speciali. In particolare, personaggi come +verranno erroneamente decodificati in spazi. Vedi la mia risposta per i dettagli.
ctrueden,

153

Per ottenere il Fileper un dato Class, ci sono due passaggi:

  1. Converti Classin aURL
  2. Converti URLin aFile

È importante comprendere entrambi i passaggi e non confonderli.

Una volta che hai il File, puoi chiamaregetParentFile per ottenere la cartella contenente, se è quello che ti serve.

Passaggio 1: ClassaURL

Come discusso in altre risposte, ci sono due modi principali per trovare un URLrilevante per a Class.

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

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

Entrambi hanno pro e contro.

L' getProtectionDomainapproccio fornisce la posizione di base della classe (ad esempio, il file JAR contenente). Tuttavia, è possibile che la politica di sicurezza del runtime Java venga lanciata SecurityExceptiondurante la chiamata getProtectionDomain(), quindi se l'applicazione deve essere eseguita in una varietà di ambienti, è meglio testarli in tutti.

L' getResourceapproccio fornisce il percorso completo delle risorse URL della classe, da cui sarà necessario eseguire un'ulteriore manipolazione delle stringhe. Potrebbe essere un file:percorso, ma potrebbe anche essere jar:file:o addirittura qualcosa di più cattivo come bundleresource://346.fwk2106232034:4/foo/Bar.classquando si esegue all'interno di un framework OSGi. Al contrario, l' getProtectionDomainapproccio produce correttamente afile: URL anche all'interno di OSGi.

Nota che entrambi getResource("")e getResource(".")fallito nei miei test, quando la classe risiedeva in un file JAR; entrambe le invocazioni hanno restituito null. Quindi raccomando invece l'invocazione n. 2 mostrata sopra, poiché sembra più sicura.

Passaggio 2: URLaFile

Ad ogni modo, una volta che hai un URL, il passaggio successivo è convertire in un File. Questa è la sua sfida; vedi il post sul blog di Kohsuke Kawaguchi per maggiori dettagli, ma in breve puoi usarlonew File(url.toURI()) fino a quando l'URL è completamente ben formato.

Infine, scoraggerei fortemente l' utilizzo URLDecoder. Alcuni caratteri dell'URL, :e /in particolare, non sono caratteri con codifica URL validi. Da URLDecoder Javadoc:

Si presume che tutti i caratteri nella stringa codificata siano uno dei seguenti: "da" a "z", da "A" a "Z", da "0" a "9" e "-", "_", " .", e "*". Il carattere "%" è consentito ma viene interpretato come l'inizio di una sequenza con escape speciale.

...

Esistono due modi in cui questo decodificatore potrebbe gestire stringhe illegali. Potrebbe lasciare da solo i personaggi illegali o lanciare un'eccezione IllegalArgumentException. L'approccio adottato dal decodificatore è lasciato all'implementazione.

In pratica, URLDecodergeneralmente non getta IllegalArgumentExceptioncome sopra minacciato. E se il percorso del file ha spazi codificati come %20, questo approccio potrebbe sembrare funzionare. Tuttavia, se il percorso del file contiene altri caratteri non alfanumerici, ad esempio, +si avranno problemi con URLDecoderla modifica del percorso del file.

Codice di lavoro

Per ottenere questi passaggi, potresti avere metodi come il seguente:

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

Puoi trovare questi metodi nella libreria SciJava Common :


5
+1; la migliore risposta fino ad oggi: restituirà il percorso usando la notazione corretta per il sistema operativo. (es. \ per windows).
Bathsheba,

Per quanto riguarda la sicurezza, credo di aver scoperto che Java WebStart non lo consentiva.
Thorbjørn Ravn Andersen,

55

Puoi anche usare:

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

3
Questo funziona meglio per me, perché dà il percorso del Jar, non della classe!
T30

Ha funzionato anche per me. Combina con la risposta di Fab e migliora!
Danielson Alves Júnior,

25

Usa ClassLoader.getResource () per trovare l'URL per la tua classe corrente.

Per esempio:

package foo;

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

(Questo esempio è tratto da una domanda simile .)

Per trovare la directory, dovrai smontare manualmente l'URL. Consulta l' esercitazione JarClassLoader per il formato di un URL jar.


Il mio file JAR è offuscato, quindi questa risposta non risolve il mio problema. Ma non l'ho specificato nella domanda, quindi questa è ancora una risposta valida.
Thiago Chaves,

12
Se è offuscato, utilizzare Test.class.getName () e eseguire il munging appropriato.
Jon Skeet,

1
@JonSkeet ci sono così tanti problemi con la tua risposta: 1. Non ci sarà NPEperché non hai risposto alla domanda che ti è stata posta (è stato chiesto il percorso alla directory JAR e hai risposto su una domanda completamente diversa: percorso alla classe). 2. Come sottolineato da altri, e ho avuto lo stesso problema, non funziona per le applet. 3. percorso restituito non è di rappresentanza percorso canonico a tutti: jar:file:/listener/build/libs/listener-1.0.0-all.jar!/shared/Test.class.
WhiteAngel

1
@WhiteAngel: 1) L'ultima riga del mio post indica che dovresti guardare l'URL e selezionarlo per ottenere il file jar. Sono d'accordo che non è la risposta più completa, ma non credo sia davvero così brutto di cui valga la pena discutere (specialmente 10 anni dopo ...) 2) Le applet non sono state menzionate in nessun commento qui - stranamente, non lo so non ho tempo di guardare tutti i commenti su tutte le risposte alle domande a cui mi è capitato di pubblicare una risposta. 3) Ancora una volta, mi collego al formato dell'URL jar.
Jon Skeet,

2
@ WhiteAngel: è la risposta migliore che abbia mai scritto? No. È così brutto come lo stai immaginando di essere? No, non la penso così. (Soprattutto in termini di affermazioni che hai fatto intorno ad esso lanciando un NPE, che non lo fa.) Suggerirei di aggiungere la tua risposta invece di fare storie su questo. Sarebbe un approccio più positivo.
Jon Skeet,

19

Sono sorpreso di vedere che nessuno ha recentemente proposto di utilizzare Path. Segue una citazione: " La Pathclasse include vari metodi che possono essere utilizzati per ottenere informazioni sul percorso, accedere agli elementi del percorso, convertire il percorso in altre forme o estrarre porzioni di un percorso "

Quindi, una buona alternativa è quella di ottenere il più Pathoggettivo come:

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

3
Come nota, Path è disponibile a partire da Java 7.
Chris Forrence,

15

L'unica soluzione che funziona per me su Linux, Mac e 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();
}

Questo non funzionerà. Se su Linux, il metodo toUri () genererà un'eccezione e non raggiungerai la parte else, per Linux.
Wilhelm Sorban,

9

Ho avuto lo stesso problema e l'ho risolto in questo modo:

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

Spero di esserti stato di aiuto.


Non farlo. URL.getPath () non restituisce un nome file e fallirà in molte circostanze, come i percorsi dei file con spazi all'interno.
VGR,

9

Ecco l'aggiornamento ad altri commenti, che mi sembrano incompleti per i dettagli di

usando una "cartella" relativa all'esterno del file .jar (nella stessa posizione del vaso):

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

4
Attenzione: non è consigliabile utilizzare URLDecoderper decodificare caratteri speciali. In particolare, personaggi come +verranno erroneamente decodificati in spazi. Vedi la mia risposta per i dettagli.
ctrueden,

L'uso di caratteri speciali nei nomi dei file non è raccomandato.
Zon,

URLDecoder, nonostante il suo nome, serve per decodificare l'URL e i nomi e i valori dei parametri dei moduli, non gli URL.
Marchese di Lorne,

6

Per ottenere il percorso di esecuzione del file jar ho studiato le soluzioni di cui sopra e ho provato tutti i metodi che esistono differenze tra loro. Se questi codici sono in esecuzione in Eclipse IDE, tutti dovrebbero essere in grado di trovare il percorso del file inclusa la classe indicata e aprire o creare un file indicato con il percorso trovato.

Ma è complicato, quando si esegue il file jar eseguibile direttamente o attraverso la riga di comando, non verrà eseguito poiché il percorso del file jar ottenuto dai metodi precedenti fornirà un percorso interno nel file jar, ovvero fornirà sempre un percorso come

rsrc: nome-progetto (forse dovrei dire che è il nome del pacchetto del file di classe principale - la classe indicata)

Non riesco a convertire il percorso rsrc: ... in un percorso esterno, ovvero quando si esegue il file jar all'esterno dell'IDE Eclipse non è possibile ottenere il percorso del file jar.

L'unico modo possibile per ottenere il percorso di esecuzione del file jar all'esterno di IDE Eclipse è

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

questa riga di codice può restituire il percorso di vita (incluso il nome del file) del file jar in esecuzione (notare che il percorso di ritorno non è la directory di lavoro), poiché il documento java e alcune persone hanno detto che restituirà i percorsi di tutti i file di classe nella stessa directory, ma come i miei test se nella stessa directory includono molti file jar, restituisce solo il percorso di esecuzione jar (a proposito del problema dei percorsi multipli effettivamente accaduto in Eclipse).


java.class.pathpuò essere multivalore. Uno di questi valori fornirà sicuramente la directory o il file JAR in cui si trova la classe corrente, ma quale?
Marchese di Lorne,

Confermo, ho provato altre soluzioni, ma non ottengo mai il nome del file jar. Funziona molto semplicemente! grazie - +1
guillaume girod-vitouchkina

5

Altre risposte sembrano puntare all'origine del codice che è la posizione del file Jar che non è una directory.

Uso

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

Può essere una directory, se stai caricando le tue classi da un filesystem anziché da un file JAR, ad esempio durante il debug.
Marchese di Lorne,

4

la risposta selezionata sopra non funziona se si esegue il vaso facendo clic su di esso dall'ambiente desktop di Gnome (non da alcuno script o terminale).

Invece, mi piace che la seguente soluzione funzioni ovunque:

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

2
L'hai provato in un'applet o in un'app. lanciato utilizzando Java Web Start? La mia comprensione è che fallirà in entrambe le situazioni (anche se l'app è attendibile).
Andrew Thompson,

Questa soluzione può restituire solo la posizione di "." all'interno del file JAR, non la posizione del file JAR.
Marchese di Lorne,

Attenzione: non è consigliabile utilizzare URLDecoderper decodificare caratteri speciali. In particolare, personaggi come +verranno erroneamente decodificati in spazi. Vedi la mia risposta per i dettagli.
ctrueden,

In Spring boot, lanceràNullPointerException
Ravi Parekh il

Avrai NPEse non ci sono risorse in JAR.
WhiteAngel,

3

In realtà qui c'è una versione migliore - quella vecchia falliva se il nome di una cartella aveva uno spazio al suo interno.

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

Per quanto riguarda il fallimento con le applet, di solito non avresti comunque accesso ai file locali. Non so molto su JWS ma per gestire i file locali potrebbe non essere possibile scaricare l'app.


Esistono diversi modi integrati per decodificare il percorso. Non c'è bisogno di scrivere il tuo codice.
Marchese di Lorne,

3

Ho cercato di ottenere il percorso di esecuzione del vaso usando

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

c: \ app> java -jar application.jar

Eseguendo l'applicazione jar denominata "application.jar", su Windows nella cartella " c: \ app ", il valore della variabile String "cartella" era " \ c: \ app \ application.jar " e ho riscontrato problemi durante il test correttezza del percorso

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

Quindi ho provato a definire "test" come:

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

per ottenere il percorso nel formato giusto come " c: \ app " anziché " \ c: \ app \ application.jar " e ho notato che funziona.


3

La soluzione più semplice è passare il percorso come argomento durante l'esecuzione del vaso.

Puoi automatizzarlo con uno script di shell (.bat in Windows, .sh altrove):

java -jar my-jar.jar .

Ho usato .per passare il directory di lavoro corrente.

AGGIORNARE

Potresti voler incollare il file jar in una sottodirectory in modo che gli utenti non lo facciano accidentalmente clic. Il codice deve inoltre verificare che gli argomenti della riga di comando siano stati forniti e fornire un buon messaggio di errore se mancano gli argomenti.


3

Ho dovuto fare molto casino prima di trovare finalmente una soluzione funzionante (e breve).
È possibile che jarLocationvenga fornito con un prefisso come file:\o jar:file\, che può essere rimosso utilizzando String#substring().

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

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

Il percorso si riferisce sempre alla risorsa all'interno del file jar.


1
Quella stringa di percorso deve ancora essere semplificata in base alle proprie esigenze. String path = new File(getClass().getResource("").getPath()).getParentFile().getParent(); File jarDir = new File(path.substring(5));
ZZZ,

4
Entrambi getResource("")e getResource(".")fallito nei miei test, quando la classe risiedeva in un file JAR; entrambe le invocazioni hanno restituito null.
ctrueden,

2
Questo genera NullPointerException.
Marchese di 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;}

Funziona bene su Windows


1

Qualcosa di frustrante è che quando si sta sviluppando in Eclipse MyClass.class.getProtectionDomain().getCodeSource().getLocation()restituisce la /bindirectory che è fantastica, ma quando la si compila in un barattolo, il percorso include la /myjarname.jarparte che ti dà nomi di file illegali.

Per far funzionare il codice sia nell'ide che una volta compilato in un barattolo, utilizzo il seguente pezzo di codice:

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

Non sono molto sicuro degli altri, ma nel mio caso non ha funzionato con un "vaso eseguibile" e l'ho fatto funzionare fissando i codici insieme dalla risposta phchen2 e un altro da questo link: Come ottenere il percorso di un file JAR in esecuzione? Il codice:

               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

Ho provato diverse soluzioni lassù, ma nessuna ha prodotto risultati corretti per il caso (probabilmente speciale) in cui il vaso eseguibile è stato esportato con "Creazione di pacchetti di librerie esterne" in Eclipse. Per qualche motivo, tutte le soluzioni basate su ProtectionDomain risultano nulle in tal caso.

Dalla combinazione di alcune soluzioni sopra sono riuscito a ottenere il seguente codice di lavoro:

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

Prova questo:

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

0

Questo metodo, chiamato dal codice nell'archivio, restituisce la cartella in cui si trova il file .jar. Dovrebbe funzionare in 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);
  } 

Derivato dal codice su: determina se in esecuzione da JAR


3
"Dovrebbe funzionare in Windows o Unix." ma fallirà in qualsiasi applet e ogni app. lanciato usando JWS.
Andrew Thompson,

0

Menzione che è registrato solo in Windowsma penso che funzioni perfettamente su altri sistemi operativi [ Linux,MacOs,Solaris] :).


Ho avuto 2 .jar file nella stessa directory. Volevo da un .jarfile iniziare l'altro.jar file che si trova nella stessa directory.

Il problema è che quando lo si avvia dalla cmddirectory corrente è system32.


Avvertenze!

  • Quanto segue sembra funzionare abbastanza bene in tutti i test che ho fatto anche con il nome della cartella ;][[;'57f2g34g87-8+9-09!2#@!$%^^&()o()%&$%^@# funziona bene.
  • Sto usando il ProcessBuildercon il seguito come segue:

🍂 ..

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

Questo codice ha funzionato per me:

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

Questo codice ha funzionato per me per identificare se il programma è in esecuzione all'interno di un file 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;
    }
}

Se ho bisogno di ottenere il percorso completo di Windows del file JAR sto usando questo metodo:

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

Il mio codice completo funziona con un'applicazione Spring Boot usando l' CommandLineRunnerimplementazione, per garantire che l'applicazione venga sempre eseguita all'interno di una vista della console (Doppi clic per errore nel nome del file JAR), sto usando il codice seguente:

@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

Scrivo in Java 7 e collaudo in Windows 7 con il runtime di Oracle e Ubuntu con il runtime open source. Questo funziona perfettamente per quei sistemi:

Il percorso per la directory padre di qualsiasi file jar in esecuzione (supponendo che la classe che chiama questo codice sia un figlio diretto dell'archivio jar stesso):

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

Quindi, il percorso di foo.jar sarebbe:

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

Ancora una volta, questo non è stato testato su nessun Mac o Windows precedente


-1

L' getProtectionDomainapproccio potrebbe non funzionare a volte, ad esempio quando è necessario trovare il vaso per alcune delle classi java di base (ad esempio nella mia StringBuilderclasse case all'interno di IBM JDK), tuttavia il seguente funziona senza problemi:

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 () non fa quello che pensi che faccia. Tutti i caratteri speciali saranno codificati in percentuale.
VGR,

-1

Ho un altro modo per ottenere la posizione String di una classe.

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

La stringa di output avrà la forma di

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

Gli spazi e gli altri personaggi vengono gestiti e nella forma senza file:/. Quindi sarà più facile da usare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.