Come ottenere il percorso di un file JAR in esecuzione?

Il mio codice viene eseguito all’interno di un file JAR, ad esempio foo.jar, e ho bisogno di sapere, nel codice, in quale cartella è in esecuzione foo.jar.

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

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

Sostituisci “MyClass” con il nome della tua class

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

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.

Per ottenere il File per una determinata Class , ci sono due passaggi:

  1. Converti la Class in un URL
  2. Converti l’ URL in un File

È importante capire entrambi i passaggi e non confonderli.

Una volta ottenuto il File , puoi chiamare getParentFile per ottenere la cartella contenente, se è ciò di cui hai bisogno.

Passaggio 1: Class to URL

Come discusso in altre risposte, ci sono due modi principali per trovare un URL relativo a una 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’approccio getProtectionDomain fornisce la posizione di base della class (ad esempio, il file JAR contenente). Tuttavia, è ansible che la politica di sicurezza del runtime Java genererà SecurityException quando si chiama getProtectionDomain() , quindi se l’applicazione deve essere eseguita in una varietà di ambienti, è meglio testarli in tutti.

L’approccio getResource fornisce il percorso completo della risorsa URL della class, da cui sarà necessario eseguire ulteriori manipolazioni delle stringhe. Può essere un file: path, ma potrebbe anche essere jar:file: o anche qualcosa di più bundleresource://346.fwk2106232034:4/foo/Bar.class come bundleresource://346.fwk2106232034:4/foo/Bar.class quando si esegue all’interno di un framework OSGi. Viceversa, l’approccio getProtectionDomain restituisce correttamente un file: URL anche da OSGi.

Notare che getResource("") e getResource(".") riusciti nei miei test, quando la class risiedeva in un file JAR; entrambe le invocazioni hanno restituito nulla. Quindi raccomando l’invocazione # 2 mostrata qui sopra, poiché sembra più sicura.

Passaggio 2: URL su File

In entrambi i casi, una volta che hai un URL , il passaggio successivo viene convertito in un File . Questa è la sua stessa sfida; vedi il post del blog di Kohsuke Kawaguchi a riguardo per i dettagli completi, ma in breve, puoi usare il new File(url.toURI()) a condizione che l’URL sia completamente ben formato.

Infine, sconsiglio vivamente di utilizzare URLDecoder . Alcuni caratteri dell’URL,: e / in particolare, non sono caratteri con codifica URL valida. Da URLDecoder Javadoc:

Si presume che tutti i caratteri nella stringa codificata siano uno dei seguenti: “a” attraverso “z”, “A” a “Z”, “0” a “9” e “-“, “_”, ” .”, e “*”. Il carattere “%” è permesso ma è interpretato come l’inizio di una sequenza speciale di escape.

Ci sono due modi possibili in cui questo decodificatore potrebbe gestire stringhe illegali. Potrebbe lasciare solo caratteri illegali o lanciare un IllegalArgumentException. Quale approccio il decodificatore prende è lasciato all’implementazione.

In pratica, URLDecoder generalmente non lancia IllegalArgumentException come minacciato sopra. E se il percorso del tuo file ha spazi codificati come %20 , questo approccio potrebbe sembrare funzionare. Tuttavia, se il percorso del tuo file ha altri caratteri non alfanumerici come + avrai problemi con URLDecoder il percorso del tuo file.

Codice di lavoro

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

 /** * Gets the base location of the given class. * 

* If the class is directly on the file system (eg, * "/path/to/my/package/MyClass.class") then it will return the base directory * (eg, "file:/path/to"). *

*

* If the class is within a JAR file (eg, * "/path/to/my-jar.jar!/my/package/MyClass.class") then it will return the * path to the JAR (eg, "file:/path/to/my-jar.jar"). *

* * @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 MalformsdURLException e) { e.printStackTrace(); return null; } } /** * Converts the given {@link URL} to its corresponding {@link File}. *

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

* * @param url The URL to convert. * @return A file path suitable for use with eg {@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 eg {@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 MalformsdURLException e) { // NB: URL is not completely well-formsd. } catch (final URISyntaxException e) { // NB: URL is not completely well-formsd. } 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 :

  • org.scijava.util.ClassUtils
  • org.scijava.util.FileUtils .

Puoi anche usare:

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

Utilizzare ClassLoader.getResource () per trovare l’URL per la class 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, devi quindi rimuovere l’URL manualmente. Vedi il tutorial JarClassLoader per il formato di un URL jar.

Sono sorpreso di vedere che nessuno recentemente ha proposto di usare Path . Segue una citazione: ” La class Path include vari metodi che possono essere utilizzati per ottenere informazioni sul percorso, accedere agli elementi del percorso, convertire il percorso in altre forms o estrarre parti di un percorso

Quindi, una buona alternativa è ottenere il Path objest come:

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

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

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 d’aiuto.

Ecco l’aggiornamento ad altri commenti, che mi sembrano incompleti per le specifiche di

utilizzando una “cartella” relativa esterna al file .jar (nella stessa posizione 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")); 

la risposta selezionata sopra non funziona se si esegue il jar facendo clic su di esso dall’ambiente desktop Gnome (non da qualsiasi 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 ""; } 

Per ottenere il percorso del file jar in esecuzione, 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 class indicata e aprire o creare un file indicato con il percorso trovato.

Ma è complicato, quando si esegue il file jar eseguibile direttamente o tramite la riga di comando, sarà fallito in quanto il percorso del file jar ottenuto dai metodi di cui sopra darà un percorso interno nel file jar, cioè dà sempre un percorso come

rsrc: nome-progetto (forse dovrei dire che è il nome del pacchetto del file principale della class – la class indicata)

Non riesco a convertire il percorso rsrc: … in un percorso esterno, cioè quando eseguo il file jar all’esterno dell’IDE di Eclipse non è ansible ottenere il percorso del file jar.

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

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

questa riga di codice può restituire il percorso vivente (incluso il nome del file) del file jar in esecuzione (si noti che il percorso di ritorno non è la directory di lavoro), come il documento java e alcune persone hanno detto che restituirà i percorsi di tutti i file di class nella stessa directory, ma siccome i miei test se nella stessa directory includono molti file jar, restituiscono solo il percorso del jar in esecuzione (sul problema dei percorsi multipli, in effetti è successo in Eclipse).

In realtà qui c’è una versione migliore – la vecchia ha fallito se il nome di una cartella avesse 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 

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

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

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

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

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

 java -jar my-jar.jar . 

Ho usato per passare la directory di lavoro corrente.

AGGIORNARE

Si consiglia di incollare il file jar in una sottodirectory in modo che gli utenti non accedano accidentalmente. Il tuo codice dovrebbe anche verificare che gli argomenti della riga di comando siano stati forniti e fornire un buon messaggio di errore se gli argomenti mancano.

Altre risposte sembrano puntare alla sorgente del codice che è la posizione del file Jar che non è una directory.

Uso

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

Ho dovuto gironzolare molto prima di trovare finalmente una soluzione funzionante (e breve).
È ansible che jarLocation un prefisso come file:\ o jar:file\ , che può essere rimosso usando String#substring() .

 URL jarLocationUrl = MyClass.class.getProtectionDomain().getCodeSource().getLocation(); String jarLocation = new File(jarLocationUrl.toString()).getParent(); 
 public static String dir() throws URISyntaxException { URI path=Main.class.getProtectionDomain().getCodeSource().getLocation().toURI(); String name= Main.class.getPackage().getName()+".jar"; String path2 = path.getRawPath(); path2=path2.substring(1); if (path2.contains(".jar")) { path2=path2.replace(name, ""); } return path2;} 

Funziona bene su Windows

Ho cercato di ottenere il percorso di esecuzione jar utilizzando

 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 avuto problemi durante il test per correttezza del percorso

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

Così ho provato a definire “test” come:

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

per ottenere il percorso in un formato corretto come ” c: \ app ” invece di ” \ c: \ app \ application.jar ” e ho notato che funziona.

Qualcosa che è frustrante è che quando si sviluppa in Eclipse MyClass.class.getProtectionDomain().getCodeSource().getLocation() restituisce la directory /bin che è grande, ma quando lo si compila in un jar, il percorso include /myjarname.jar parte /myjarname.jar che ti dà nomi di file illegali.

Per fare in modo che il codice funzioni sia in ide e una volta compilato in un jar, io uso il seguente 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"); } 

Non proprio sicuro degli altri, ma nel mio caso non ha funzionato con un “Runnable jar” e l’ho fatto lavorando risolvendo 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"); 

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: Determinare se si esegue da JAR

Si noti che è controllato solo in Windows ma penso che funzioni perfettamente su altri sistemi operativi [ Linux,MacOs,Solaris ] :).


Ho avuto 2 file .jar nella stessa directory. Volevo dal file .jar per avviare l’altro file .jar che si trova nella stessa directory.

Il problema è che quando lo si avvia dal cmd la directory corrente è system32 .


Avvertenze!

  • Il sotto 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 ProcessBuilder con 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 

🍂 classi 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 + "classs")) { basePath = basePath.substring(0, basePath.length() - 14); } // end fix if (!basePath.endsWith(File.separator)) { basePath = basePath + File.separator; } return basePath; } 

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

Ignora risposta lad backup, a volte può sembrare ok ma ha diversi problemi:

qui entrambi dovrebbero essere +1 non -1:

 name = name.substring(name.lastIndexOf(':')-1, name.lastIndexOf('/')+1).replace('%', ' '); 

Molto pericoloso perché non è immediatamente evidente se il percorso non ha spazi bianchi, ma sostituire solo il “%” ti lascerà con un mazzo di 20 in ogni spazio bianco:

 name = name.substring(name.lastIndexOf(':')-1, name.lastIndexOf('/')+1).replace('%', ' '); 

Ci sono modi migliori di quel ciclo per gli spazi bianchi.

Inoltre causerà problemi al momento del debug.

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 principale di qualsiasi file jar in esecuzione (supponendo che la class che chiama questo codice sia figlia diretta 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 potrebbe essere:

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

Di nuovo, questo non è stato testato su nessun Mac o Windows precedente

L’approccio getProtectionDomain potrebbe non funzionare a volte ad es. Quando devi trovare il jar per alcune delle classi java core (ad es. Nel mio caso la class StringBuilder in IBM JDK), tuttavia i seguenti lavori funzionano perfettamente:

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

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

 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 sono gestiti e nella forma senza file:/ . Quindi sarà più facile da usare.

Oppure puoi passare il thread attuale in questo modo:

 String myPath = Thread.currentThread().getContextClassLoader().getResource("filename").getPath(); 

Questo liner funziona per cartelle contenenti spazi o caratteri speciali (come ç o õ). La domanda originale richiede il percorso assoluto (directory di lavoro), senza il file JAR stesso. Tested in here with Java7 on Windows7:

 String workingDir = System.getProperty("user.dir"); 

Reference: http://www.mkyong.com/java/how-to-get-the-current-working-directory-in-java/