Table of Contents

Ficheros

Tipos de ficheros

Desde el punto de vista de un programador solamente distinguiremos entre dos tipos de ficheros:

Extensión Tipo de fichero
.txt Fichero de texto plano
.xml Fichero XML
.json Fichero de intercambio de información
.props Fichero de propiedades
.conf Fichero de configuración
.sql Script SQL
.srt Fichero de subtítulo
Extensión Tipo de fichero
.pdf Fichero PDF
.jpg Fichero de imagen
.doc, .docx Fichero de Microsoft Word
.avi Fichero de video
.ppt, .pptx Fichero de PowerPoint

A veces, en ficheros binarios, podremos encontrarnos con las extensiones .bin o .dat para hacer referencia a ficheros que contienen información binaria en un formato que no está ampliamente difundido. Serán simplemente ficheros que una aplicación determinada es capaz de leer/escribir de una forma específica solo definida para dicha aplicación.

System Properties

En cualquier caso, para el acceso a ficheros independientemente del tipo de los mismos, conviene conocer el funcionamiento de las System Properties de las que dispone Java en su API. Éstas permiten acceder a propiedades de la configuración del sistema y, entre otras, podemos encontrarnos con algunas muy interesantes relacionadas con este tema:

En el caso de que se quiera acceder al valor de alguna de estas propiedades debe hacerse utilizando la llamada al método System.getProperty(String)

System.out.println("La carpeta de mi usuario es " + System.getProperty("user.home"));

Ficheros de texto

En esta parte vamos a trabajar con 3 tipos de ficheros de texto:

Existen más tipos de ficheros de texto también muy extendidos como .json y .csv pero no serán estudiados en esta parte.

Ficheros de texto plano

Los ficheros de texto son aquellos que únicamente contienen texto, por lo que pueden ser editados directamente con cualquier editor de texto plano (Bloc de Notas, notepad++, . . .). Se podría decir que son aquellos ficheros que podrían ser leídos por cualquier persona. Son aquellos que normalmente se almacenan con la extensión .txt pero también podríamos incluir los scripts SQL (.sql), ficheros de código Java (.java), ficheros de configuración (.ini, .props, .conf, . . .), . . .

También se incluyen en la categoría de ficheros de texto los que además incluyen información adicional (siempre en forma de texto) que permiten interpretar los datos del fichero de una manera u otra, añadiendo más información al mismo. Estos formatos son HTML, XML, JSON, . . .

En cualquier caso, desde Java siempre se podrán leer/escribir de la misma manera, según veremos a continuación. También veremos como pueden leerse/escribirse utilizando librerías aquellos ficheros de texto plano que contienen formato, como hemos comentado anteriormente, haciendo de esa forma mucho más fácil el trabajo.

Escribir ficheros de texto plano

FileWriter fichero = null;
PrintWriter escritor = null;
 
try {
  fichero = new FileWriter("archivo.txt");
  escritor = new PrintWriter(fichero) ;
  escritor.println("Esto es una linea del fichero");
} catch (IOException ioe) {
  ioe.printStackTrace() ;
} finally {
if (fichero != null)
  try {
    fichero.close();
  } catch (IOException ioe) { . . . }
}

Leer ficheros de texto plano

File fichero = null;
FileReader lector = null;
BufferedReader buffer = null;
 
try {
  buffer = new BufferedReader(new FileReader(new File("archivo.txt")));
  String linea = null;
  while ((linea = buffer.readLine()) != null)
    System.out.println(linea);
} catch (FileNotFoundException fnfe) { 
  fnfe.printStackTrace();
} catch (IOException ioe) { 
  ioe.printStackTrace(); 
} finally {
  if (buffer != null)
  try {
    buffer.close();
  } catch (IOException ioe) { . . . }
}

Ficheros de configuración

En la API de Java se incluyen librerías para trabajar con los ficheros de configuración. Puesto que todos siguen un mismo patrón, es la librería la que se encarga de acceder al fichero a bajo nivel y el programador sólo tiene que indicar a que propiedad quiere acceder o que propiedad quiere modificar, sin tener que añadir nada de código para leer o escribir el fichero tal y como hemos visto en el punto anterior.

Un ejemplo de fichero de configuración de esta librería de java sería el fichero que sigue:

configuracion.props
# Fichero de configuracion
# Thu Nov 14 10:49:39 CET 2013
 
user=usuario
password=micontrasena
server=localhost
port=3306

Escribir ficheros de configuración

Así, si queremos generar, desde Java, un fichero de configuración como el anterior:

. . .
Properties configuracion = new Properties();
configuracion.setProperty("user", miUsuario);
configuracion.setProperty("password", miContrasena);
configuracion.setProperty("server", elServidor);
configuracion.setProperty("port", elPuerto);
try {
  configuracion.store(new FileOutputStream("configuracion.props"), 
                                           "Fichero de configuracion");
} catch (FileNotFoundException fnfe ) { 
  fnfe.printStackTrace(); 
} catch (IOException ioe) { 
  ioe.printStackTrace();
}
. . .

Leer ficheros de configuración

A la hora de leerlo, en vez de tener que recorrer todo el fichero como suele ocurrir con los ficheros de texto, simplemente tendremos que cargarlo e indicar de qué propiedad queremos obtener su valor (getProperty(String)).

. . .
Properties configuracion = new Properties();
try {
  configuracion.load(new FileInputStream("configuracion.props"));
  usuario = configuracion.getProperty("user");
  password = configuracion.getProperty("password");
  servidor = configuracion.getProperty("server");
  puerto = Integer.valueOf(configuration.getProperty("port"));
} catch (FileNotFoundException fnfe ) { 
  fnfe.printStackTrace();
} catch (IOException ioe) { 
  ioe.printStackTrace();
}
. . .

Para ambos casos, escribir y leer este tipo de ficheros, hay que tener en cuenta que, al tratarse de ficheros de texto, toda la información se almacena como si de un String se tratara. Por tanto, todos aquellos tipos Date, boolean o incluso cualquier tipo numérico serán almacenados en formato texto. Así, habrá que tener en cuenta las siguientes consideraciones:

Ficheros XML

Los ficheros XML permiten el intercambio de información entre aplicaciones utilizando para ello un fichero de texto plano al que se le pueden añadir etiquetas para darle significado a cada uno de los valores que se almacenan.

Por ejemplo, el siguiente fichero XML podría ser el resultado de volcar una Base de Datos sobre productos de una compañia, de forma que dicha información podría ahora leerse desde otra aplicación e incorporarla. Se puede ver como a parte de los datos de dichos productos (sus nombres, precios, . . .) aparece otra información en forma de etiquetas (entre los caracteres < y >) que permite dar significado a cada dato almacenado en el fichero. Así, podemos saber de qué estamos hablando y a qué corresponde cada valor.

Obviamente, tal y como ocurría con los ficheros de configuración, toda la información se tiene que pasar a texto para poder crear el fichero y reconvertida a su tipo original cuando se cargue de nuevo. Las mismas consideraciones que hemos tenido en cuenta antes nos servirán ahora (ver aqui)

productos.xml
<?xml version="1.0" encoding="UTF-8" standalone="no">
<xml>
<productos>
  <producto>
    <nombre>Cereales</nombre>
    <precio>3.45</precio>
  </producto>
  <producto>
    <nombre>Colacao</nombre>
    <precio>1.45</precio>
  </producto>
  <producto>
    <nombre>Agua mineral</nombre>
    <precio>1.00</precio>
  </producto>
</productos>
</xml>

La clase Java que definiría cada uno de los objetos que se representan por el fichero XML anterior, sería la siguiente:

Producto.java
public class Producto {
  private String nombre;
  private float precio;
 
  public Producto(String nombre, float precio) {
    this.nombre = nombre;
    this.precio = precio;
  }
 
  public String getNombre () { return nombre; }
  public void setNombre (String nombre) { this.nombre = nombre; }
 
  public float getPrecio () { return precio; }
  public void setPrecio (float precio) { this.precio = precio; }
}

Escribir ficheros XML

Si ahora queremos generar el fichero XML con toda la información de una colección de objetos Producto, podemos utilizar el siguiente código:

. . .
documento = dom.createDocument(null, "xml", null);
Element raiz = document.createElement("productos");
documento.getDocumentElement().appendChild(raiz);
Element nodoProducto = null , nodoDatos = null ;
Text texto = null;
 
for (Producto producto : listaProductos) {
  nodoProducto = documento.createElement("producto");
  raiz.appendChild(nodoProducto);
  nodoDatos = documento.createElement("nombre");
  nodoProducto.appendChild(nodoDatos);
  texto = documento.createTextNode(producto.getNombre());
  nodoDatos.appendChild(texto);
  nodoDatos = documento.createElement("precio");
  nodoProducto.appendChild(nodoDatos);
  texto = documento.createTextNode(producto.getPrecio());
  nodoDatos.appendChild(texto);
}
. . .

Leer ficheros XML

Y si lo que queremos es leer un fichero XML y cargarlo como una colección Java de objetos Producto, el ejemplo siguiente muestra un breve ejemplo acerca de cómo acceder a la información de dicho fichero XML.

. . .
NodeList productos = documento.getElementyByTagName("producto");
for (int i = 0; i < productos.getLength(); i++) {
  Node producto = productos . item ( i ) ;
  Element elemento = ( Element ) producto ;
  System.out.println(elemento.getElementsByTagName("nombre").item(0)
                     .getChildNodes().item(0).getNodeValue());
  System.out.println(elemento.getElementsByTagName("precio").item(0)
                     .gethildNodes().item(0).getNodeValue());
}
. . .

Ficheros binarios

Producto.java
public class Producto implements Serializable {
  private static final long serialVersionUID = 1L;
  private String nombre;
  private float precio;
 
  public Producto(String nombre, float precio) {
    this.nombre = nombre;
    this.precio = precio;
  }
 
  public String getNombre() { return nombre; }
  public void setNombre(String nombre) { this.nombre = nombre; }
 
  public float getPrecio() { return precio ; }
  public void setPrecio(float precio) { this.precio = precio; }
}

Serialización de objetos

Serializar es el proceso por el cual un objeto en memoria pasa a transformarse en una estructura que pueda ser almacenada en un fichero (persistencia). Al proceso contrario le llamaremos deserializar.

Hay que tener en cuenta que durante el proceso de serialización, cada objeto se serializa a un fichero, por lo que si queremos almacenar todos los objetos de una aplicación, la idea más conveniente es tener todos éstos en alguna estructura compleja (y por comodidad dinámica) de forma que sea esta estructura la que serialicemos o deserialicemos para guardar o cargar los objetos de una aplicación. Estructuras como ArrayList, Set ó HashMap son clases muy utilizadas para trabajar de esta manera.

Serializar un objeto

. . .
ObjectOutputStream serializador = null;
try {
  serializador = new ObjectOutputStream(new FileOutputStream("archivo.dat"));
  serializador.writeObject(listaProductos);
} catch (IOException ioe) { 
  . . .
} finally {
  if (serializador != null)
    try {
      serializador.close();
    } catch (IOException ioe) {
      ioe.printStackTrace();
    }
  }
. . .

Deserializar un objeto

. . .
List<Producto> listaProductos = null;
ObjectInputStream deserializador = null;
try {
  deserializador = new ObjectInputStream(new FileInputStream("archivo.dat"));
  listaProductos = (ArrayList<Producto>)deserializador.readObject();
} catch (FileNotFoundException fnfe ) {
  fnfe.printStackTrace();
} catch (ClassNotFoundException cnfe ) { 
  cnfe.printStackTrace();
} catch (IOException ioe) { 
  ioe.printStackTrace();
} finally {
  if (deserializador != null)
  try {
    deserializador.close();
  } catch (IOException ioe) { 
    ioe.printStackTrace();
  }
}
. . .

Paquete Java NIO 2

No includo desde siempre, el paquete Java NIO 2, mejora las clases y métodos disponibles para trabajar con ficheros, sistemas de ficheros y todo lo relacionado con entrada/salida.

FileSystems

Es una factoría que permite acceder a un sistema de ficheros:

FileSystem

Representa un sistema de ficheros

Paths

Contiene métodos estáticos para obtener objetos Path a partir de cadenas

Path

Representa un fichero dentro del sistema de ficheros. Podemos acceder al fichero y a su información a través de las propiedades y métodos de la clase

Files

Contiene métodos estáticos que operan con ficheros y directorios


© 2019-2024 Santiago Faci