Como obter o caminho de um arquivo JAR em execução?

580

Meu código é executado dentro de um arquivo JAR, digamos foo.jar , e eu preciso saber, no código, em qual pasta está o foo.jar em execução .

Portanto, se foo.jar estiver dentro C:\FOO\, eu quero pegar esse caminho, independentemente do meu diretório de trabalho atual.

Thiago Chaves
fonte
Veja a resposta de Fab para uma solução que funciona quando os caminhos incluem espaços. Além disso, observe que algumas respostas abaixo abordam a pergunta no título (caminho do jar), algumas abordam a questão em si (caminho da pasta que contém o jar) e algumas fornecem caminhos para as classes dentro do arquivo jar.
Andy Thomas
32
Cuidado ao usar no ANT! ============== Eu chamo String path = SomeClass.class.getProtectionDomain (). GetCodeSource (). GetLocation (). GetPath (); e obtenha: /C:/apache-ant-1.7.1/lib/ant.jar Não é muito útil!
Dino Fancellu
Interessante. O código original em que eu usei isso nunca foi executado no form, por isso não é um problema para mim.
Thiago Chaves
2
@ Dino Fancellu, experimentei exatamente o que você descreveu. Funciona durante o desenvolvimento, falha quando criado para jar.
amigos

Respostas:

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

Substitua "MyClass" pelo nome da sua turma.

Obviamente, isso fará coisas estranhas se a sua classe foi carregada de um local que não é do arquivo.

Zarkonnen
fonte
43
A toURI()etapa é vital para evitar problemas com caracteres especiais, incluindo espaços e vantagens. O alinhamento correto é: O return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI()); uso URLDecodernão funciona para muitos caracteres especiais. Veja minha resposta abaixo para mais detalhes.
usar o seguinte comando
4
Nota: isso retorna o caminho, incluindo o nome do arquivo jar
Buddy
8
Isso não aponta para o arquivo jar, em vez do diretório em execução? Você precisará fazer um resultado no getParentFile () para este trabalho.
FOO
1
Além disso, getProtectionDomainé nulo se você está recebendo sua classe a partir de um stracktrace:val strace = Thread.currentThread().getStackTrace; val path = strace(1).getClass.getProtectionDomain
bbarker
1
Usando este método com até Java 8; Ao colocar esse método em uma classe que está em um Jar externo, carregado pelo caminho da classe, o caminho do jar externo será fornecido em vez do Jar em execução.
Mr00Anderson
189

Melhor solução para mim:

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

Isso deve resolver o problema com espaços e caracteres especiais.

Fab
fonte
8
Mais uma observação: Ao chamar esta função do Jar, o nome do jar é anexado no final para mim, portanto, era necessário executar: path.substring (0, path.lastIndexOf ("/") + 1);
will824
11
/ não é necessariamente o separador de caminho. Você deve fazer (novo arquivo (caminho)). GetParentFile (). GetPath ().
pjz
10
Nenhum problema com o nome do arquivo JAR sendo anexado aqui. A conversão UTF parece ser a solução perfeita em combinação com a @Iviggiani one ( URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");) no Linux. No entanto, eu não tentei no Windows.
Ubuntudroid
2
Obrigado, isso me permitiu carregar arquivos externos ao meu JAR com o FileInputStream no Linux e no Windows. Apenas teve que adicionar o decodedpath na frente do nome do arquivo ...
giorgio79
11
Cuidado: não é recomendável usar URLDecoderpara decodificar caracteres especiais. Em particular, caracteres como +serão erroneamente decodificados para espaços. Veja minha resposta para detalhes.
ctrueden
153

Para obter Fileum dado Class, há duas etapas:

  1. Converta ClassemURL
  2. Converta URLemFile

É importante entender os dois passos, e não confundi-los.

Depois de ter o File, você pode ligar getParentFilepara obter a pasta que contém, se é isso que precisa.

Etapa 1: ClassparaURL

Conforme discutido em outras respostas, há duas maneiras principais de encontrar um URLrelevante para a Class.

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

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

Ambos têm prós e contras.

A getProtectionDomainabordagem gera a localização base da classe (por exemplo, o arquivo JAR que contém). No entanto, é possível que a política de segurança do tempo de execução Java seja lançada SecurityExceptionao chamar getProtectionDomain(), portanto, se seu aplicativo precisar executar em uma variedade de ambientes, é melhor testar em todos eles.

A getResourceabordagem gera o caminho completo do recurso de URL da classe, a partir do qual você precisará executar uma manipulação adicional de strings. Pode ser um file:caminho, mas também pode ser jar:file:ou até algo mais desagradável bundleresource://346.fwk2106232034:4/foo/Bar.classao executar dentro de uma estrutura OSGi. Por outro lado, a getProtectionDomainabordagem gera corretamente uma file:URL mesmo dentro do OSGi.

Observe que ambos getResource("")e getResource(".")falharam nos meus testes, quando a classe residia em um arquivo JAR; ambas as invocações retornaram nulas. Por isso, recomendo a invocação nº 2 mostrada acima, pois parece mais segura.

Etapa 2: URLparaFile

De qualquer forma, depois de ter um URL, o próximo passo é converter para a File. Este é o seu próprio desafio; consulte a publicação no blog de Kohsuke Kawaguchi para obter detalhes completos, mas, em suma, você pode usar new File(url.toURI())desde que a URL esteja completamente bem formada.

Por fim, eu desencorajaria o uso URLDecoder. Alguns caracteres da URL :e , /em particular, não são caracteres codificados por URL válidos. No URLDecoder Javadoc:

Supõe-se que todos os caracteres na cadeia codificada sejam um dos seguintes: "a" a "z", "A" a "Z", "0" a "9" e "-", "_", " . "e" * ". O caractere "%" é permitido, mas é interpretado como o início de uma sequência de escape especial.

...

Existem duas maneiras possíveis pelas quais esse decodificador pode lidar com cadeias ilegais. Ele pode deixar caracteres ilegais em paz ou lançar uma IllegalArgumentException. A abordagem adotada pelo decodificador é deixada para a implementação.

Na prática, URLDecodergeralmente não joga IllegalArgumentExceptioncomo ameaçado acima. E se o caminho do arquivo tiver espaços codificados como %20, essa abordagem pode parecer funcionar. No entanto, se o caminho do arquivo tiver outros caracteres não alfanuméricos, como +você terá problemas ao URLDecodermanipular o caminho do arquivo.

Código de trabalho

Para realizar essas etapas, você pode ter métodos como o seguinte:

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

Você pode encontrar esses métodos na biblioteca comum do SciJava :

ctrueden
fonte
5
+1; a melhor resposta até o momento: ele retornará o caminho usando a notação correta para o sistema operacional. (por exemplo, \ para janelas).
Bathsheba
Em relação à segurança, acredito que descobri que o Java WebStart não permitia isso.
Thorbjørn Ravn Andersen
55

Você também pode usar:

CodeSource codeSource = YourMainClass.class.getProtectionDomain().getCodeSource();
File jarFile = new File(codeSource.getLocation().toURI().getPath());
String jarDir = jarFile.getParentFile().getPath();
Benny Neugebauer
fonte
3
Isso funciona melhor para mim, porque dá o caminho do Jar, não da classe!
T30
Trabalhou para mim também. Combine com a resposta de Fab e ficará melhor!
Danielson Alves Júnior
25

Use ClassLoader.getResource () para encontrar o URL da sua classe atual.

Por exemplo:

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 exemplo foi retirado de uma pergunta semelhante .)

Para encontrar o diretório, você precisará desmontar o URL manualmente. Consulte o tutorial JarClassLoader para obter o formato de uma URL jar.

Jon Skeet
fonte
Meu arquivo JAR está ofuscado, portanto, esta resposta não resolve o meu problema. Mas eu não especifiquei isso na pergunta, então essa ainda é uma resposta válida.
Thiago Chaves
12
Se estiver ofuscado, use Test.class.getName () e faça a remoção apropriada.
Jon Skeet
1
@JonSkeet, há muitos problemas com sua resposta: 1. Não haverá NPEporque você não respondeu à pergunta que foi feita (o caminho para o diretório JAR foi solicitado e você respondeu com uma pergunta absolutamente diferente: caminho para a aula). 2. Como apontado por outros, e eu tenho o mesmo problema, ele não funciona para applets. 3. caminho retornado não é de representação caminho canônico em tudo: jar:file:/listener/build/libs/listener-1.0.0-all.jar!/shared/Test.class.
WhiteAngel
1
@WhiteAngel: 1) A última linha da minha postagem indica que você precisa procurar a URL e separá-la para obter o arquivo jar. Concordo que não é a resposta mais completa, mas não acho que seja tão ruim valer a pena discutir (especialmente 10 anos depois ...) 2) Applets não foram mencionados em nenhum comentário aqui - por incrível que pareça, eu não tenho tempo para analisar todos os comentários em todas as respostas sobre perguntas nas quais postou uma resposta. 3) Novamente, vinculo ao formato da URL do jar.
Jon Skeet
2
@WhiteAngel: É a melhor resposta que eu já escrevi? Não. É tão ruim quanto você está fazendo parecer? Não, eu não penso assim. (Particularmente em termos das reivindicações que você fez em torno de lançar um NPE, o que não acontece.) Sugiro que você adicione sua própria resposta em vez de se preocupar com essa. Essa seria uma abordagem mais positiva.
Jon Skeet
19

Estou surpreso ao ver que nenhum recentemente propôs usar Path. Segue uma citação: " A Pathclasse inclui vários métodos que podem ser usados ​​para obter informações sobre o caminho, acessar elementos do caminho, converter o caminho para outras formas ou extrair partes de um caminho "

Portanto, uma boa alternativa é obter o Pathobjetivo como:

Path path = Paths.get(Test.class.getProtectionDomain().getCodeSource().getLocation().toURI());
mat_boy
fonte
3
Como uma nota, Caminho está disponível partida em Java 7.
Chris Forrence
15

A única solução que funciona para mim no 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();
}
Dmitry Trofimov
fonte
Isso não vai funcionar. Se no Linux, o método toUri () lançará uma exceção e você não alcançará a parte else, para linux.
Wilhelm Sorban
9

Eu tive o mesmo problema e resolvi da seguinte maneira:

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

Espero ter ajudado você.

Charlie
fonte
Não faça isso. URL.getPath () não retorna um nome de arquivo e falhará em várias circunstâncias, como caminhos de arquivo com espaços neles.
VGR 13/06
9

Aqui está a atualização para outros comentários, que me parecem incompletos para as especificações de

usando uma "pasta" relativa fora do arquivo .jar (no mesmo local do 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"));
Zon
fonte
4
Cuidado: não é recomendável usar URLDecoderpara decodificar caracteres especiais. Em particular, caracteres como +serão erroneamente decodificados para espaços. Veja minha resposta para detalhes.
ctrueden
O uso de caracteres especiais nos nomes dos arquivos não é recomendado.
Zon
URLDecoder, apesar do nome, é para decodificar nomes e valores de URLs e de parâmetros de formulário, não URLs.
Marquês de Lorne
6

Para obter o caminho da execução do arquivo jar, estudei as soluções acima e tentei todos os métodos que existem alguma diferença entre si. Se esses códigos estiverem em execução no Eclipse IDE, todos deverão encontrar o caminho do arquivo, incluindo a classe indicada, e abrir ou criar um arquivo indicado com o caminho encontrado.

Mas é complicado, quando executar o arquivo jar executável diretamente ou através da linha de comando, ele falhará, pois o caminho do arquivo jar obtido pelos métodos acima fornecerá um caminho interno no arquivo jar, ou seja, sempre fornece um caminho Como

rsrc: nome do projeto (talvez eu deva dizer que é o nome do pacote do arquivo principal da classe - a classe indicada)

Não consigo converter o caminho rsrc: ... em um caminho externo, ou seja, ao executar o arquivo jar fora do IDE Eclipse, ele não pode obter o caminho do arquivo jar.

A única maneira possível de obter o caminho da execução do arquivo jar fora do IDE Eclipse é

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

essa linha de código pode retornar o caminho ativo (incluindo o nome do arquivo) do arquivo jar em execução (observe que o caminho de retorno não é o diretório ativo), como o documento java e algumas pessoas disseram que retornará os caminhos de todos os arquivos de classe no mesmo diretório, mas como meus testes se no mesmo diretório incluem muitos arquivos jar, ele retorna apenas o caminho da execução do jar (sobre o problema de vários caminhos, de fato, aconteceu no Eclipse).

phchen2
fonte
java.class.pathpode ter vários valores. Um desses valores certamente fornecerá o diretório ou arquivo JAR em que a classe atual está localizada, mas qual?
Marquês de Lorne
Confirmo que tentei outras soluções, mas nunca obtive o nome do arquivo jar. Isso funciona de maneira muito simples! obrigado - +1
guillaume girod-vitouchkina 16/04/2015
5

Outras respostas parecem apontar para a fonte de código, que é o local do arquivo Jar, que não é um diretório.

Usar

return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile();
FOO
fonte
Pode ser um diretório, se você estiver carregando suas classes de um sistema de arquivos em vez de um arquivo JAR, por exemplo, durante a depuração.
Marquês de Lorne
4

a resposta selecionada acima não funcionará se você executar seu jar clicando nele no ambiente de área de trabalho Gnome (não em nenhum script ou terminal).

Em vez disso, gosto que a seguinte solução esteja funcionando em qualquer lugar:

    try {
        return URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");
    } catch (UnsupportedEncodingException e) {
        return "";
    }
lviggiani
fonte
2
Você tentou isso em um applet ou em um aplicativo. lançado usando o Java Web Start? Meu entendimento é que ele falhará nas duas situações (mesmo que o aplicativo seja confiável).
Andrew Thompson
Esta solução só pode retornar a localização de "." dentro do arquivo JAR, não no local do arquivo JAR.
Marquês de Lorne
Cuidado: não é recomendável usar URLDecoderpara decodificar caracteres especiais. Em particular, caracteres como +serão erroneamente decodificados para espaços. Veja minha resposta para detalhes.
ctrueden
Na inicialização Spring, ele vai jogarNullPointerException
Ravi Parekh
Você terá NPEse não houver recursos no JAR.
WhiteAngel
3

Na verdade, aqui está uma versão melhor - a antiga falhou se o nome de uma pasta tivesse um espaço nela.

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

Quanto à falha nos applets, você normalmente não teria acesso aos arquivos locais de qualquer maneira. Não sei muito sobre o JWS, mas, para lidar com arquivos locais, talvez não seja possível baixar o aplicativo.

rapaz bacup
fonte
Existem várias maneiras internas de decodificar o caminho. Não há necessidade de escrever seu próprio código.
Marquês de Lorne
3

Eu tentei pegar o caminho do jar usando

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

c: \ app> java -jar application.jar

Executando o aplicativo jar denominado "application.jar", no Windows na pasta " c: \ app ", o valor da variável String "pasta" era " \ c: \ app \ application.jar " e tive problemas ao testar correção do caminho

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

Então, eu tentei definir "teste" como:

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

para obter o caminho no formato correto como " c: \ app " em vez de " \ c: \ app \ application.jar " e notei que funcionava.

TheGreatPsychoticBunny
fonte
3

A solução mais simples é passar o caminho como argumento ao executar o jar.

Você pode automatizar isso com um script de shell (.bat no Windows, .sh em qualquer outro lugar):

java -jar my-jar.jar .

Eu costumava .passar o diretório de trabalho atual.

ATUALIZAR

Você pode colocar o arquivo jar em um subdiretório para que os usuários não cliquem nele acidentalmente. Seu código também deve verificar se os argumentos da linha de comando foram fornecidos e fornecer uma boa mensagem de erro se os argumentos estiverem ausentes.

Max Heiber
fonte
3

Eu tive que mexer muito antes de finalmente encontrar uma solução funcional (e curta).
É possível que ele jarLocationvenha com um prefixo como file:\ou jar:file\, que pode ser removido usando String#substring().

URL jarLocationUrl = MyClass.class.getProtectionDomain().getCodeSource().getLocation();
String jarLocation = new File(jarLocationUrl.toString()).getParent();
Jelle
fonte
2
String path = getClass().getResource("").getPath();

O caminho sempre se refere ao recurso dentro do arquivo jar.

ZZZ
fonte
1
Essa cadeia de caminho ainda precisa ser simplificada para sua necessidade. String path = new File(getClass().getResource("").getPath()).getParentFile().getParent(); File jarDir = new File(path.substring(5));
ZZZ
4
Ambos getResource("")e getResource(".")falharam nos meus testes, quando a classe residia em um arquivo JAR; ambas as invocações retornaram nulas.
precisa
2
Isso joga 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 bem no Windows

Denton
fonte
1

Algo frustrante é que, quando você está desenvolvendo no Eclipse, MyClass.class.getProtectionDomain().getCodeSource().getLocation()retorna o /bindiretório que é ótimo, mas quando você o compila em um jar, o caminho inclui a /myjarname.jarparte que fornece nomes de arquivos ilegais.

Para que o código funcione tanto no ide quanto depois de compilado em um jar, use o seguinte trecho 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");
}
Alexander
fonte
1

Não tenho muita certeza dos outros, mas, no meu caso, ele não funcionou com um "jar executável" e eu consegui trabalhar corrigindo códigos juntos da resposta phchen2 e outra a partir deste link: Como obter o caminho de um arquivo JAR em execução? O 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");
Fahad Alkamli
fonte
1

Tentei várias soluções lá em cima, mas nenhuma produziu resultados corretos para o caso (provavelmente especial) de que o jar executável foi exportado com "Empacotando bibliotecas externas" no Eclipse. Por algum motivo, todas as soluções baseadas no ProtectionDomain resultam em nulo nesse caso.

Ao combinar algumas soluções acima, consegui obter o seguinte código de trabalho:

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);
DragonGamer
fonte
1

Tente o seguinte:

String path = new File("").getAbsolutePath();
Blarzek
fonte
0

Esse método, chamado de código no arquivo morto, retorna a pasta onde está o arquivo .jar. Deve funcionar no Windows ou no 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 do código em: Determine se está sendo executado a partir do JAR

Bacup Lad
fonte
3
"Ele deve funcionar no Windows ou no Unix." mas falhará em qualquer applet e em todos os aplicativos. lançado usando o JWS.
21811 Andrew Thompson
0

Mencione que ele está marcado apenas para dentro, Windowsmas acho que funciona perfeitamente em outros sistemas operacionais [ Linux,MacOs,Solaris] :).


Eu tinha 2 .jar arquivos no mesmo diretório. Eu queria que um .jararquivo iniciasse o outro .jararquivo que está no mesmo diretório.

O problema é que, quando você o inicia cmdno diretório atual, é system32.


Advertências!

  • O abaixo parece funcionar muito bem em todos os testes que fiz, mesmo com o nome da pasta ;][[;'57f2g34g87-8+9-09!2#@!$%^^&()ou ()%&$%^@# funciona bem.
  • Estou usando o ProcessBuildercom o seguinte, como a seguir:

🍂 ..

//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;
    }
GOXR3PLUS
fonte
0

Este código funcionou para mim:

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;
  }
John Lockwood
fonte
0

Este código funcionou para mim para identificar se o programa está sendo executado dentro de um arquivo JAR ou 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 eu precisar obter o caminho completo do arquivo JAR do Windows, estou 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;
        }
    }

Meu código completo trabalhando com um aplicativo Spring Boot usando CommandLineRunnerimplementação, para garantir que o aplicativo sempre seja executado dentro de uma visualização do console (cliques duplos por engano no nome do arquivo JAR), estou usando o próximo 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;
        }
    }
}
Jairo Martínez
fonte
-1

Escrevo em Java 7 e testo no Windows 7 com o tempo de execução da Oracle e no Ubuntu com o tempo de execução de código aberto. Isso funciona perfeito para esses sistemas:

O caminho para o diretório pai de qualquer arquivo jar em execução (assumindo que a classe que chama esse código é um filho direto do próprio arquivo 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

Portanto, o caminho do foo.jar seria:

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

Novamente, isso não foi testado em nenhum Mac ou Windows mais antigo

sudoBen
fonte
-1

A getProtectionDomainabordagem pode não funcionar, por vezes, por exemplo, quando você tem que encontrar o pote para algumas das classes Java núcleo (por exemplo, no meu caso StringBuilderclasse dentro IBM JDK), no entanto seguintes obras perfeitamente:

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, "");
}
Vasu
fonte
URL.getPath () não faz o que você pensa que faz. Quaisquer caracteres especiais serão codificados em porcentagem.
VGR 13/06
-1

Eu tenho outra maneira de obter o local String de uma classe.

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

A String de saída terá a forma de

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

Os espaços e outros caracteres são manipulados e na forma sem file:/. Então será mais fácil de usar.

NoSegfault
fonte