Archive for category Java SE

Classe Properties

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.

5 Comentários