Caros,
Fiz uma aplicação em Java que le um arquivo de configuração, e se ele não existe, a aplicação cria.
Depois disso, fiz um instalador com o Inno Setup, que cria um atalho para a minha aplicação no desktop.
O problema é:
O arquivo de configuração está sendo criado no desktop, e isso não é o que eu quero. Isso acontece por que eu crio o arquivo no diretório “.”, que passa a ser o Desktop quando o programa é executado a partir do atalho.
Alguém sabe me dizer como fazer o .jar gerar o arquivo de configurações dentro da pasta que está o .jar? Essa pasta é dinâmica e depende da instalação. Estou procurando algum comando que me retorne a pasta real que o .jar está mas não estou conseguindo.
Agradeço qualquer ajuda.
Sua configuração é global (ou seja, depois da instalação não pode ser mais mexida) ou é por usuário?
Se for global, continue a verificar a história do jar.
Se for por usuário, veja o pacote java.util.prefs ( http://java.sun.com/javase/6/docs/api/java/util/prefs/package-summary.html )
EDIT - Mesmo se for global eu recomendo usar o pacote prefs. Ele salva as configurações no registry no caso do Windows, e em arquivos XML no caso do Unix/Linux.
por padrão, vc encontrara o .jar na pasta do projeto, dentro da pasta “dist”…
pelo menos se for pelo netbeans é lá…
vlw
Achei uma solução, mas não fui muito com a cara dela…
Aqui está:
public class PastaCorrente {
public PastaCorrente() {
try {
String caminho = PastaCorrente.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath();
caminho = caminho.substring(1, caminho.lastIndexOf('/') + 1);
System.out.println(caminho);
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
}
Uma forma estúpida de obter isso é pegar, via getResource, a URL de algum recurso dentro desse JAR, e então pegar o nome do JAR a partir do objeto URL. que esse método retornou.
Não sei que tipo de arquivo é o que está sendo criado, mas vc pode fazer algo assim:
...
FileOutputStream out;
PrintStream printStream;
out = new FileOutputStream(new File(nomeDoArquivo).getAbsoluteFile(), true);
printStream = new PrintStream(out);
printStream.println(conteudo);
printStream.close();
}
O .getAbsoluteFile() que é um método da classe File vai criar seu arquivo no nivel da aplicação, ou seja, no mesmo diretório que estaria o pacote .jar de sua aplicação.
[quote=romarcio]
O .getAbsoluteFile() que é um método da classe File vai criar seu arquivo…[/quote]
- getAbsoluteFile não cria arquivos
- Ele apenas verifica se o File corresponde a um diretório ou arquivo existente no disco, e se corresponder, expande o diretório para o path completo.
Usar new File (".").getAbsoluteFile() só vai lhe retornar o diretório corrente, que pode ser o diretório onde você iniciou o JAR se você deu um duplo clique, ou então algum outro. Portanto, não é muito confiável.
Veja: http://java.sun.com/javase/6/docs/api/java/io/File.html#getAbsoluteFile()
[quote=entanglement][quote=romarcio]
O .getAbsoluteFile() que é um método da classe File vai criar seu arquivo…[/quote]
- getAbsoluteFile não cria arquivos
- Ele apenas verifica se o File corresponde a um diretório ou arquivo existente no disco, e se corresponder, expande o diretório para o path completo.
Usar new File (".").getAbsoluteFile() só vai lhe retornar o diretório corrente, que pode ser o diretório onde você iniciou o JAR se você deu um duplo clique, ou então algum outro. Portanto, não é muito confiável.
Veja: http://java.sun.com/javase/6/docs/api/java/io/File.html#getAbsoluteFile()[/quote]
Sim, se ele usar assim por exemplo :
File file = new File("arquivo.jar");
String s = file.getAbsolutePath();
A string s, vai passar pra ele o local exato de onde está o arquivo .jar, então ele poderá criar seu arquivo a partir desse diretório.
Esse
File arquivo = new File("arquivo.jar");
if (arquivo.exists()) {
System.out.println(arquivo.getAbsolutePath());
} else {
System.out.println("O arquivo não existe");
}
só irá funcionar se eu estiver rodando o .jar da pasta corrente dele. Caso contrário, ele irá retornar a pasta corrente com o nome “arquivo.jar” no final.
Exemplo:
estou no desktop: java -jar arquivo.jar -> retorna c:\users\augusto\desktop\arquivo.jar
estou na minha users: java -jar desktop\arquivo.jar -> retorna o arquivo não existe
Por enquanto a única solução que realmente funciona foi aquela solução bizzara que falei no começo:
public class PastaCorrente {
public PastaCorrente() {
try {
String caminho = PastaCorrente.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath();
caminho = caminho.substring(1, caminho.lastIndexOf('/') + 1);
System.out.println(caminho);
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
}
Por que funciona? por que quando eu chamo PastaCorrente.class a máquina virtual do java pergunta diretamente à máquina virtual do java o nome do caminho do lugar aonde essa classe está no disco. Pra máquina virtual carregar, ela precisa saber esse endereço absoluto.
É virtualmente impossível descobrir o caminho onde está o .jar que disparou a aplicação, isso inclusive está na minha lista de coisas que odeio em Java. O java é feito justamente para você não ter esse caminho. Eu fiz um método que até funciona razoavelmente bem, e se baseia no que o Entanglement falou:
private static String findJarParentPath(File jarFile)
{
while (jarFile.getPath().contains(".jar"))
jarFile = jarFile.getParentFile();
return jarFile.getPath().substring(6);
}
/**
* Return the instalation path of any class.
*
* @param theClass The class to find the installation path.
* @return The installation path of any class.
*/
public static String getInstallPath(Class< ? > theClass)
{
String url = theClass.getResource(theClass.getSimpleName() + ".class").getPath();
File dir = new File(url).getParentFile();
if (dir.getPath().contains(".jar"))
return findJarParentPath(dir).replace("%20", " ");
return dir.getPath().replace("%20", " ");
}
O uso é simples. Passe como parâmetro para o método qualquer classe que esteja dentro do pacote. Geralmente eu passo da minha classe onde está o main.
Ah sim, a solução ficou desajeitada justamente pq nosso security manager não permitia acesso ao protection domain.
O.o… acabei de dar uma solução que pergunta diretamente à JVM!
vou mostrar denovo:
public class PastaCorrente {
public PastaCorrente() {
try {
String caminho = this.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().getPath();
caminho = caminho.substring(1, caminho.lastIndexOf('/') + 1);
System.out.println(caminho);
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new PastaCorrente();
}
}
Rodem isso e vejam que funciona.
Eu só estou perguntando se alguém sabe uma solução que não precise dessa parafernalha toda…
Se você puder usar o pacote java.util.prefs você nem precisa ficar com um arquivo de configuração, pode salvar as coisas no registry (no caso do Windows) ou em um arquivo XML (no caso do Linux/Unix). Isso pode ser interessante se você não quer que o pessoal fique mexendo com sua configuração.
vc tem algum exemplo de uso?
Peguei um exemplo de uso neste site: http://www.particle.kth.se/~lindsey/JavaCourse/Book/Part1/Java/Chapter10/Preferences.html
está acontecendo este erro:
13/07/2010 17:18:11 java.util.prefs.WindowsPreferences
WARNING: Could not create windows registry node Software\JavaSoft\Prefs\pasta/Corrente at root 0x80000002. Windows RegCreateKeyEx(…) returned error code 5.
13/07/2010 17:18:11 java.util.prefs.WindowsPreferences WindowsRegOpenKey1
WARNING: Trying to recreate Windows registry node Software\JavaSoft\Prefs\pasta/Corrente at root 0x80000002.
13/07/2010 17:18:11 java.util.prefs.WindowsPreferences openKey
WARNING: Could not open windows registry node Software\JavaSoft\Prefs\pasta/Corrente at root 0x80000002. Windows RegOpenKey(…) returned error code 2.
Isso ocorre se sua aplicação não tiver as permissões corretas para criar algumas chaves no Registry. Portanto, você só pode criar configurações de sistema se você fizer isso durante a instalação.
[quote=Augusto_]Rodem isso e vejam que funciona.
Eu só estou perguntando se alguém sabe uma solução que não precise dessa parafernalha toda…
vou mostrar denovo: [/quote]
Por acaso você leu o que escrevi no post seguinte? Sua “solução” requisita o ProtectionDomain. Aproveite que você postou novamente o código, e leia-o.
Esse método só funciona se o SecurityManager autorizar e, como eu havia ressaltado no post seguinte, o nosso não autorizava.
E, como eu falei, no Java é virtualmente impossível achar esse caminho.
Por isso é necessário essa “parafernalha” toda, que geralmente não funcionam em todos os casos.