Archivos de propiedades en Java
Tags: java, espanol
Published: 2019-09-06 17:44:31

Muchas veces necesítanos conservar información después de la ejecución de nuestros programas y el utilizar una base de datos para una pequeña aplicación no suele ser la mejor opción sería como comprar un Ferrari para ir a nuestro lugar de trabajo que se encuentra a 2km de distancia.

Para estas situaciones Java nos permite almacenar información en archivos properties o archivos de propiedades, estos no son más que archivos de texto es decir podemos abrirlos y editarlos con el blog de notas así de simple y como son archivos la información en ellos no se perderá después de la ejecución de nuestra aplicación el utilizarlos es muy simple solo necesitaremos unas cuantas clases de 2 paquetes de java.

1. java.util
    * Properties
2. java.io
    * FileInputStream
    * FileOutputStream
    * InputStream
    * OutputStream
    * IOException

Para empezar a realizar esta tarea crearemos una clase en la cual se encuentren los métodos que nos permitirán acceder al valor de una propiedad, así como también el agregar nuevas propiedades o cambiar su valor

```java
import java.util.Properties;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;

public class FicheroDePreferencias {

    

}
```

Crearemos cuatro objetos privados, el primero será un objeto de tipo `Sting` en el que almacenaremos la ruta del archivo que utilizaremos como nuestro archivo de propiedades.

El segundo objeto será uno de tipo `Properties` ya que en esta clase se encuentran los métodos necesarios para hacer set y get a las propiedades del archivo.

El tercer objeto será un `InputStream` por medio de este objeto la clase Properties puede leer el archivo.

Como contraparte del objeto InputStream necesitamos uno que nos permita guardar la información en el archivo para realizar esta acción necesitamos un objeto de tipo `OutputStream`.

```java
import java.util.Properties;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;

public class FicheroDePreferencias {

    private String directorio = null;
    private Properties fichero = null;
    private InputStream leerFichero = null;
    private OutputStream escribirFichero = null;

}
```

Para indicarle al objeto de tipo Properties cual sera el archivo de propiedades crearemos un meto en el que le diremos desde que archivo leer

```java
public class FicheroDePreferencias {

    private String directorio = null;
    private Properties fichero = null;
    private InputStream leerFichero = null;
    private OutputStream escribirFichero = null;
    
    private void leerDesde(String directorio) {
        try {
            leerFichero = new FileInputStream(directorio);
            fichero.load(leerFichero);
        } catch (IOException e) {
            System.err.println("No se pudo cargar el archivo.");
            e.printStackTrace();
        }
    }
}
```

El objeto leerFichero de tipo `InputStream` se inicializa con un objeto de tipo `FileInputStrem` ya que la clase IntputStream es una clase abstracta y estas no pueden instanciarse la única manera es instanciar por medio de una clase hija que no sea abstracta, el constructor de la clase FileInputStream recibe como parámetro la dirección del archivo de propiedades, al ejecutar el método `load` el objeto fichero de tipo Properties almacena las propiedades con su valor para que podamos utilizarlas en el momento que queramos.

La estructura `try/catch` evita que el programa se cierre al no encontrar el archivo indicado. Al tener las propiedades en objeto fichero crearemos un método que nos permita obtener el valor de cualquier propiedad

```java
public class FicheroDePreferencias {

    private String directorio = null;
    private Properties fichero = null;
    private InputStream leerFichero = null;
    private OutputStream escribirFichero = null;
    
    public String getPropiedad(String propiedad) {
        String value = null;
        try {
            value = fichero.getProperty(propiedad);
        } catch (Exception e) {
            System.err.println("Error al acceder al archivo.");
            e.printStackTrace();
        }
        return value;
    }
}
```

El método para realizar esta tarea es muy simple creamos un objeto de tipo String llamado values en el que se almacenara el valor de la propiedad, y este valor lo obtenemos con el método `getProperty` este método recibe un parámetro el cual es el nombre de la propiedad.

Solo nos quedaría el realizar el método setPropiedad, ya que para este método lo que realizaremos es agregar o actualizar la información y después guardarla necesitaremos el objeto escribirFichero de tipo `OutputStream` y al igual que InputStream, OutputStream también es una clase abstracta por lo cual creamos un objeto de tipo `FileOutputStream` y el constructor de este recibe como parámetro la dirección donde se encuentra el archivo de propiedades.


```java
public class FicheroDePreferencias {

    private String directorio = null;
    private Properties fichero = null;
    private InputStream leerFichero = null;
    private OutputStream escribirFichero = null;
    
    public void setPropiedad(String propiedad, String valor, String comentario) {
        try {
            escribirFichero = new FileOutputStream(directorio);
            fichero.setProperty(propiedad, valor);
            fichero.store(escribirFichero, comentario);
        } catch (IOException e) {
            System.err.println("Error al guardar cambios.");
            e.printStackTrace();
        }
    }
    
    public void setPropiedad(String propiedad, String valor) {
        setPropiedad(propiedad, valor, null);
    }
    
}
```

El método `setPropiedad` recibe 3 parámetros de tipo String el primero es el nombre de la propiedad a agregar o actualizar el segundo es su valor y el tercero es un comentario en el archivo.

Para agregar los cambios al archivo utilizamos el método `setProperty` de la clase Properties y para guardar los cambios utilizamos el método `store` de la misma clase. La estructura `try/catch` se asegura que el programa no se cierre bruscamente si algo sale mal. Realizamos una sobrecarga del método por si acaso no queremos dar un comentario. 

Por ultimo crearemos un constructor donde inicializaremos el objeto de tipo `Properties` y la variable `directorio` también ejecutaremos el método `leerDesde`

```java
public class FicheroDePreferencias {

    private String directorio = null;
    private Properties fichero = null;
    private InputStream leerFichero = null;
    private OutputStream escribirFichero = null;
    
    public FicheroDePreferencias(String directorio) {
        fichero = new Properties();
        this.directorio = directorio;
        
        leerDesde(directorio);
    }
    
}
```

Ejecutar este método en el constructor es muy importante ya que si no ejecutáramos el método `load` de la clase Properties antes que se ejecute la línea donde se inicializa el objeto escribirFichero  de tipo `OutputStream ` perderemos su contenido ya que constructor de la clase OutputStream evalúa si el archivo esta vacío y si no lo está borra su contenido dejándolo en blanco al ejecutar el método load guardamos el contenido del archivo en el objeto fichero y al ejecutar el método `setProperty` agregamos la nueva información al objeto fichero cuando ejecutamos el método `store` se reescribe toda la información guardada en el objeto fichero. El código final quedaría así: 



```java
import java.util.Properties;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;

public class FicheroDePreferencias {
    
    private String directorio = null;
    private Properties fichero = null;
    private InputStream leerFichero = null;
    private OutputStream escribirFichero = null;
    
    private void leerDesde(String directorio) {
        try {
            leerFichero = new FileInputStream(directorio);
            fichero.load(leerFichero);
        } catch (IOException e) {
            System.err.println("No se pudo cargar el archivo.");
            e.printStackTrace();
        }
    }
    
    public String getPropiedad(String propiedad) {
        String value = null;
        try {
            value = fichero.getProperty(propiedad);
        } catch (Exception e) {
            System.err.println("Propiedad no encontrada.");
            e.printStackTrace();
        }
        return value;
    }

    public void setPropiedad(String propiedad, String valor, String comentario) {
        try {
            escribirFichero = new FileOutputStream(directorio);
            fichero.setProperty(propiedad, valor);
            fichero.store(escribirFichero, comentario);
        } catch (IOException e) {
            System.err.println("Error al guardar cambios.");
            e.printStackTrace();
        }
    }
    
    public void setPropiedad(String propiedad, String valor) {
        setPropiedad(propiedad, valor, null);
    }    
    
    public FicheroDePreferencias(String directorio) {
        fichero = new Properties();
        this.directorio = directorio;
        
        leerDesde(directorio);
    }
    
}
```

¿Solo faltaría probar la clase no? Bien para esto utilizare una clase llamada Test que tendrá el método principal y un ejemplo de lo que podemos hacer con los archivos properties.

```java
import java.util.Scanner;

public class Test{

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        FicheroDePreferencias miFichero = new FicheroDePreferencias("Test.properties");
        String nombre = miFichero.getPropiedad("nombre");
        if (nombre != null) {
            System.out.println("Bienvenido " + nombre + " te dije que no lo olvidaria :D");
        }
        else{
            System.out.println("Hola cual es tu nombre? ");
            nombre = sc.nextLine();
            miFichero.setPropiedad("nombre", nombre);
            System.out.println("Entendido no lo olvidare! :D");
        }
        sc.close();
    }
}
```

![Imagen de ejecucion](https://thepracticaldev.s3.amazonaws.com/i/dgii55djznkfwg3atx6n.png)

Nuestro archivo Test.Properties se ve así después de la primer ejecución:

![Imagen de archivo properties](https://thepracticaldev.s3.amazonaws.com/i/ht9998nyj3oxv4bdzlr7.png)

Nota: Los archivos Test.java, FicheroDePreferencias.java y Test.properties se encuentran todo en la misma carpeta, este ejercicio se desarrolló con Visual Studio Code, el archivo Test.properties en la primera ejecución del programa existe, pero está en blanco