Archive for category Java SE
Classe Properties
Posted by Diego Ferreira da Silva in Java, Java SE on 28 de março de 2009
Veremos neste post como pode ser útil a utilização da classe Properties para ler arquivos de configuração.
A classe
A classe java.util.Properties, presente desde a versão 1.0 do JDK, é filha (extende) da classe java.util.Hashtable e, por consequência, implementa a interface Map. Ela armazena pares de valores, assim como a Hashtable, com uma diferença: ambos os valores (chave e valor) são Strings.
Para quem nunca usou nenhum Map, é interessante saber que um Map associa dois objetos: dado uma chave, pego um valor. Um exemplo de Mapa que poderia ser representado em java:
| norte = tesouro sul = pirata oeste = pirata leste = oasis |
Como podemos ver, um Map é um conjunto de pares chave->valor associados. Uma chave só tem um valor, mas podem existir várias chaves que tem o mesmo valor. No nosso caso, sul e oeste tem o mesmo valor.
O Properties é um mapa especial, pois não associa dois objetos, e sim duas Strings.
Alguns dos métodos da classe Properties:
//retorna null caso não exista um objeto na coleção em que a chave
// tenha o valor "nome" no nosso caso, retornaria "tesouro"
String nome = props.getProperty("norte");
// caso não exista chave com o valor "sudoeste",
// em vez de retornar null, retorna sempre o valor "vazio"
String nome2 = props.getProperty("sudoeste", "vazio");
// adiciona ao mapa a chave "extremoSul", com valor
// "caverna". Caso já exista um elemento na coleção
// com esta chave, o valor na coleção é alterado para este último
props.setProperty("extremoSul", "caverna");
// retorna um Enumeration, sem ordem definida, com as chaves das propriedades
Enumeration enum = props.propertyNames();
// lê os dados de um determinado InputStream
// veremos neste tutorial o formato que este arquivo deve ter
props.load(InputStream in);
// o head representa a comentário que será inserido no começo do arquivo,
// junto com a hora em que os dados foram armazenados.
props.store(OutputStream out, String head);
O método save(OutputStream out, String header) está depreciado (deprecated) porque ele não gera uma IOException caso aconteça algum problema.
Os métodos put() e get(), herdados da classe Hashtable, podem ser utilizados ao invés de setProperty() e getProperty(), desde que os objetos inseridos sejam Strings, caso contrário será gerada uma ClassCastException no momento em que for feita a leitura dos valores presentes na coleção, em razão do tipo dos objetos inseridos não serem Strings.
Estratégia
É possível ler pares de valores armazenados em arquivos texto, a partir do método load(), desde que seja declarado um par de valores por linha no arquivo e que a chave seja separada do valor pelo caracter igual (=). Exemplo: O arquivo mail.properties possui as seguintes configurações:
| #Configurações do arquivo mail.properties mail.pop3.host=pop.dot.com mail.debug=false mail.from=from_user@mail.dot.com mail.user=to_user mail.smtp.host=smtp.dot.com mail.store.protocol=pop3 |
Para inserir um comentário de uma linha no arquivo, utilize a cerquilha (#). Se houver gravação no arquivo, o conteúdo anterior será apagado inclusive os comentários.
Convencionou-se colocar a terminação .properties a esses arquivos textos de configurações utilizados pelo java, assim como existem os arquivos .ini no windows. É possível encontrar os arquivos .properties no JBoss, Tomcat e em outros projetos.
Atenção: os dados do arquivo .properties serão utilizados na aplicação de acordo com as regras da classe String, por exemplo, user é diferente de User.
Utilizando Properties, não é possível garantir a ordem em que os dados serão armazenados, quer dizer, se vocês armazenarem a coleção do mesmo objeto properties em momentos diferentes da aplicação, o conteúdo do arquivo poderá estar em ordens diferentes. Se a ordem for importante, veja a classe LinkedHashMap, que foi adicionada ao jdk1.4. Ela devolve um iterator com os valores ordenados pela ordem de inserção na HashMap.
Lendo um arquivo .properties
Para ler um arquivo, é necessário criar um InputStream a ser lido e um objeto da classe Properties. O passo seguinte é chamar o método load() da classe Properties para ler os dados que estão no arquivo.
// o arquivo encontra-se no mesmo diretório
//da aplicação
File file = new File("mail.properties");
Properties props = new Properties();
FileInputStream fis = null;
try {
fis = new FileOutputStream(file);
//lê os dados que estão no arquivo
props.load(fis);
fis.close(0;
}
catch (IOException ex) {
System.out.println(ex.getMessage());
ex.printStackTrace();
}
Agora é possível manipular os dados que foram lidos do arquivo.
String user = props.getProperty("mail.user");
String from = props.getProperty("mail.from");
String smtp = props.getProperty("mail.smtp.host");
String pop3 = props.getProperty("mail.pop3.host");
String protocol = props.getProperty("mail.store.protocol");
String debug = props.getProperty("mail.debug");
Para alterar o valor de user no objeto props, utilize o método setProperty():
String user = "guj";
props.setProperty("mail.user", user);
Notem que o valor anterior de “mail.user” foi perdido.
A sequência a seguir mostra como persistir os dados do objeto props em um arquivo diferente:
//o arquivo encontra-se no mesmo diretório da aplicação
File file = new File("mail2.properties");
FileInputStream fos = null;
try {
fos = new FileOutputStream(file);
//grava os dados no arquivo
props.store(fos,"Configurações do arquivo mail.properties");
fos.close();
}
catch (IOException ex) {
System.out.println(ex.getMessage());
ex.printStackTrace();
}
Conclusão
A utilização da classe Properties com um arquivo de configurações permite mais facilidade para manter a aplicação sem a necessidade de recompilar o código fonte a cada mudança nas configurações. Basta alterar o arquivo com as configurações e reiniciar a aplicação. Existem formas de atualizar o conteúdo do objeto properties sem reiniciar a aplicação e serão abordadas em um outro post.
