You are on page 1of 24

Acceso a datos.

Tema 1: Ficheros
Por Nacho Cabanes

Es frecuente que los programas necesiten almacenar los datos que manipulan, de modo que
estos puedan ser consultados posteriormente. Una primera forma sencilla de conseguirlo es
empleando ficheros.

1.1. Escritura en ficheros de texto


Java incluye muchas clases relacionadas con la entrada y salida en fichero. No veremos todas
ellas, sino slo las que segn nuestro criterio pueden resultar ms tiles y ms sencillas.

Un fichero de texto se puede manejar de forma muy similar a la consola, volcando datos lnea
a lnea con println. Una de las formas ms sencillas de conseguirlo en Java es empleando un
PrintWriter. A diferencia de otros lenguajes como C#, es obligatorio usar un try-catch para
interceptar los posibles errores (al menos FileNotFoundException, que se puede reemplazar
por IOException, ms general):

import java.io.PrintWriter;
import java.io.FileNotFoundException;

public class PrintWriter1 {


public static void main(String[] args) {
try {
PrintWriter printWriter = new PrintWriter ("ejemplo.txt");
printWriter.println ("Hola!");
printWriter.close ();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}

Una alternativa menos elegante, pero ms compacta, por lo que puede ser til en fuentes de
pequeo tamao, es no interceptar la excepcin, sino permitir que el propio main pueda
lanzarla, aadiendo throws, as:

import java.io.PrintWriter;
import java.io.FileNotFoundException;

public class PrintWriter1b {


public static void main(String[] args) throws FileNotFoundException {
PrintWriter printWriter = new PrintWriter ("ejemplo.txt");
printWriter.println ("Hola!");
printWriter.close ();
}
}

Acceso a datos, Tema 1 (versin 1.00) - Pgina 1


Siendo estrictos, puede existir un problema con ese primer programa: si se produce un error
durante la escritura, el fichero podra quedar abierto y existir una pequea fuga de memoria.
Para evitarlo, es preferible cerrar el fichero en el bloque final opcional de try-catch-finally.

De paso, podemos interceptar cualquier error de entrada / salida con IOException, e importar
todo lo relacionado con la entrada y salida haciendo import java.io.*;

import java.io.*;

public class PrintWriter2 {


public static void main(String[] args) {

PrintWriter printWriter = null;


try {
printWriter = new PrintWriter ("ejemplo.txt");
printWriter.println ("Hola!");
printWriter.println ("y...");
printWriter.println ("hasta luego!");
}
catch (IOException e) {
e.printStackTrace();
}
finally {
if ( printWriter != null ) {
printWriter.close();
}
}
}
}

El constructor habitual de PrintWriter destruye el contenido fichero, en caso de que ste


existiera. Si, por el contrario, se desea aadir al final de un fichero existente, se debe emplear
otro constructor, que no recibir la ruta del fichero, sino un BufferedWriter, que se apoya en
un FileWriter que tiene true como segundo parmetro: new FileWriter("ejemplo.txt,
true)). P

import java.io.*;

public class PrintWriter3 {


public static void main(String[] args) {

PrintWriter printWriter = null;


try {
printWriter = new PrintWriter(new BufferedWriter(
new FileWriter("ejemplo3.txt", true)));
printWriter.println ("Hola otra vez!");
printWriter.println ("y...");
printWriter.println ("hasta luego!");
}
catch (IOException e) {
e.printStackTrace();
}
finally {
if ( printWriter != null ) {
printWriter.close();
}

Acceso a datos, Tema 1 (versin 1.00) - Pgina 2


}
}
}

Tambin se podra haber empleado directamente un BufferedWriter para escribir, sin


necesidad de usar la clase PrintWriter, pero se trata de una clase de ms bajo nivel, que se
parece menos al manejo habitual de la consola, porque no incluye un mtodo println, sino
que se debe usar write para escribir y newLine para avanzar de lnea, como muestra este
ejemplo bsico:

import java.io.*;

class BufferedWriter1 {

public static void main( String[] args ) {


try {
BufferedWriter ficheroSalida = new BufferedWriter(
new FileWriter(new File("ejemplo2.txt")));

ficheroSalida.write("Lnea 1");
ficheroSalida.newLine();
ficheroSalida.write("Lnea 2");
ficheroSalida.newLine();

ficheroSalida.close();
}
catch (IOException errorDeFichero) {
System.out.println(
"Ha habido problemas: " +
errorDeFichero.getMessage() );
}
}
}

Ejercicios propuestos

1.1.1. Crea un programa que pida dos frases al usuario y las guarde en un fichero llamado
dosFrases.txt.

1.1.2. Crea un programa que pida frases al usuario (una cantidad indeterminada, hasta que
introduzca una lnea vaca) y las almacene en un fichero llamado frases.txt. Cada vez que se
lance el programa, se destruir el fichero frases.txt y se crear uno nuevo que lo reemplace.

1.1.3. Crea una variante del ejercicio 1.1.2, en la que el fichero se llamar anotaciones.txt y
no se destruir en cada nueva ejecucin, sino que se aadirn las nuevas frases al final de las
existentes.

1.1.4. Crea una versin mejorada del ejercicio 1.1.3, en la que antes de cada frase se anotar la
fecha y la hora en la que se ha realizado dicha anotacin.

Acceso a datos, Tema 1 (versin 1.00) - Pgina 3


1.1.5. Crea un programa que pida al usuario una anchura y una altura y cree un fichero
llamado rectangulo.txt que contenga un rectngulo de asteriscos de ese anchura y el altura.
Por ejemplo, si el usuario indica anchura 5 y altura 3, el fichero contendra:

*****
*****
*****

1.1.6. Crea un programa que pregunte al usuario la cantidad de das de un mes, el nmero del
primer da (1 para lunes, 7 para domingo) y el nombre del mes (por ejemplo, Marzo) y cree
un fichero de texto llamado agendaMarzo.txt (o el nombre del mes que corresponde), que
contendr un esqueleto de agenda para ese mes. Por ejemplo, si el mes es Septiembre, tiene
31 das y empieza en el da 4, el contenido del fichero sera algo como:

Septiembre

-----------------------------------------------------------
Jueves 1:
-----------------------------------------------------------
Viernes 2:
-----------------------------------------------------------
Sbado 3:
-----------------------------------------------------------
Domingo 4:
-----------------------------------------------------------
Lunes 5:
-----------------------------------------------------------
(...)
-----------------------------------------------------------
Viernes 30:
-----------------------------------------------------------

1.1.7. Crea un programa que pregunte al usuario la cantidad de das de un mes, el nmero del
primer da (1 para lunes, 7 para domingo) y el nombre del mes (por ejemplo, Marzo) y cree
un fichero de texto llamado calendarioMarzo.txt (o el nombre del mes que corresponde),
con el calendario de ese mes. Por ejemplo, si el mes es Septiembre, tiene 31 das y empieza en
el da 4, el contenido del fichero sera algo como:

Septiembre

lun mar mie jue vie sab dom

1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30

Acceso a datos, Tema 1 (versin 1.00) - Pgina 4


1.2. Lectura de ficheros de texto
Una forma sencilla de leer de un fichero, si nos basta con hacerlo lnea a lnea, es emplear un
BufferedReader, que se apoyar en un FileReader y que incluye un mtodo readLine que
nos devuelve una cadena de texto (un String).

Si ese String es null, quiere decir que se ha acabado el fichero y no se ha podido leer nada. Por
eso, lo habitual es usar un while para leer todo el contenido de un fichero:

import java.io.*;

class BufferedReader1 {

public static void main( String[] args ) {

// Primero vemos si el fichero existe


if (! (new File("ejemplo.txt")).exists() ) {
System.out.println("No he encontrado ejemplo.txt");
return;
}

// En caso de que exista, intentamos leer


System.out.println("Leyendo fichero...");

try {
BufferedReader ficheroEntrada = new BufferedReader(
new FileReader(new File("ejemplo.txt")));

String linea = ficheroEntrada.readLine();


while (linea != null) {
System.out.println(linea);
linea = ficheroEntrada.readLine();
}

ficheroEntrada.close();
}
catch (IOException errorDeFichero) {
System.out.println(
"Ha habido problemas: " +
errorDeFichero.getMessage() );
}

System.out.println("Fin de la lectura.");
}
}

Es habitual abreviar la lectura y la comprobacin, hacindolas en una misma orden, lo que


resulta ms compacto pero menos legible:

String linea=null;
while ((linea=ficheroEntrada.readLine()) != null) {
System.out.println(linea);
}

Acceso a datos, Tema 1 (versin 1.00) - Pgina 5


Ejercicios propuestos

1.2.1: Crea un programa que muestre la primera lnea del contenido del fichero
DosFrases.txt.

1.2.2: Crea un programa que muestre todo el contenido del fichero anotaciones.txt.

1.2.3: Crea un programa que muestre paginado el contenido del fichero anotaciones.txt: tras
cada 23 lneas se realizar una pausa hasta que el usuario pulse Intro.

1.2.4: Crea un programa que muestre el contenido de un fichero de texto, cuyo nombre
deber introducir el usuario. Debe avisar si el fichero no existe.

1.2.5: Crea un programa que lea el contenido de un fichero de texto y lo vuelque a otro fichero
de texto, pero convirtiendo cada lnea a maysculas.

1.2.6: Crea un programa que pida al usuario el nombre de un fichero y una palabra a buscar en
l. Debe mostrar en pantalla todas las lneas del fichero que contengan esa palabra.

1.2.7: Crea un programa que lea el contenido del fichero rectangulo.txt que creaste en el
ejercicio 1.1.5 y que muestre en pantalla cual es la anchura y la altura del tringulo de
asteriscos.

Acceso a datos, Tema 1 (versin 1.00) - Pgina 6


1.3. Leer de un fichero binario
Un fichero binario es un fichero que contiene cualquier cosa, no slo texto. Se puede
acceder a ellos con un fichero de tipo FileInputStream y leer byte a byte con read(). El dato
se deber leer como int, y un valor de -1 indicar que se ha alcanzado el final del fichero.

import java.io.*;

class FileInputStream1
{

public static void main( String[] args )


{
// Cantidad de "a" en un fichero de cualquier tipo,
// comprobando errores slo con try-catch

System.out.println("Contando \"a\"...");
int contador = 0;

try
{
FileInputStream ficheroEntrada2 =
new FileInputStream(new File("fichero.bin"));

int dato = ficheroEntrada2.read();

while (dato != -1) {


if (dato == 97) // Codigo ASCII de "a"
contador++;
dato = ficheroEntrada2.read();
}
ficheroEntrada2.close();
}
catch (Exception errorDeFichero)
{
System.out.println(
"Ha habido problemas: " +
errorDeFichero.getMessage() );
}

System.out.println("Cantidad de \"a\": " + contador);


}
}

Nuevamente, tambin se puede abreviar la lectura y la comprobacin, as:

int dato;
while ((dato = ficheroEntrada2.read()) != -1) {
if (dato == 97) // Codigo ASCII de "a"
contador++;
}

Este ejemplo cuenta la cantidad de letras a que contiene un fichero de cualquier tipo, ya sea
de texto, ejecutable, documento creado con un procesador de textos o cualquier otro fichero.

Acceso a datos, Tema 1 (versin 1.00) - Pgina 7


Ejercicios propuestos

1.3.1: Prepara un programa que compruebe si un fichero EXE parece vlido: deber comprobar
que su primer byte tenga el valor 0x4D y el segundo sea un 0x5A.

1.3.2: Haz un programa que lea el contenido de un fichero binario, mostrando en pantalla todo
lo que sean caracteres imprimibles (basta con que sean desde la A hasta la Z, junto con el
espacio en blanco) e ignorando todos los dems caracteres. El nombre del fichero de entrada
lo elegir el usuario.

1.3.3: Crea un programa que extraiga el contenido de un fichero binario, volcando a un fichero
de texto todo lo que sean caracteres imprimibles (basta con que sean desde la A hasta la Z,
junto con el espacio en blanco) e ignorando todos los dems caracteres. El nombre del fichero
de entrada lo elegir el usuario y el fichero de salida tendr ese mismo nombre, pero
terminado en .txt (por ejemplo, si el fichero original era 1.zip, el de salida ser 1.zip.txt).

1.3.4: Abre una imagen GIF y comprueba si sus tres primeros bytes son las letras G, I, F.

1.3.5: Crea un programa que diga si un fichero (binario) contiene una cierta palabra que
introduzca el usuario, buscando byte a byte.

Acceso a datos, Tema 1 (versin 1.00) - Pgina 8


1.4. Leer y escribir bloques en un fichero binario
Si es necesario leer muchos datos de un fichero de cualquier tipo, acceder byte a byte puede
resultar muy lento. Una alternativa mucho ms eficiente es usar un array de bytes. En este
caso, se emplear un InputStream, y su mtodo read, indicndole en qu array se desea
guardar los datos, desde qu posicin del array (que casi siempre ser la cero) y qu cantidad
de datos:

Si no conseguimos leer tantos datos como hemos intentado, ser porque hemos llegado al
final del fichero. Por eso, un programa que duplicara ficheros, leyendo cada vez un bloque de
512 Kb podra ser:

import java.io.*;

class FicheroBinarioBloques
{

public static void main( String[] args )


{
// Copiar todo un fichero, con bloques de 512 Kb,
// sin (casi) ninguna comprobacin de errores

System.out.println("Copiando fichero binario...");


final int BUFFER_SIZE = 512*1024;

try
{
InputStream ficheroEntrada3 = new FileInputStream(
new File("fichero.in"));
OutputStream ficheroSalida3 = new FileOutputStream(
new File("fichero2.out"));

byte[] buf = new byte[BUFFER_SIZE];


int cantidadLeida;
while ((cantidadLeida = ficheroEntrada3.read(buf, 0,
BUFFER_SIZE)) > 0) {
ficheroSalida3.write(buf, 0, cantidadLeida);
}
ficheroEntrada3.close();
ficheroSalida3.close();
}
catch (Exception errorDeFichero)
{
System.out.println(
"Ha habido problemas: " +
errorDeFichero.getMessage() );
}

System.out.println("Terminado!");
}
}

Acceso a datos, Tema 1 (versin 1.00) - Pgina 9


Ejercicios propuestos

1.4.1: Crea un programa que lea los primeros 54 bytes de un fichero BMP (su cabecera) y
compruebe si los dos primeros bytes de esos 54 corresponden a las letras B y M. Si no es as,
mostrar el mensaje No es un BMP vlido; si lo son, escribir el mensaje Parece un BMP
vlido.

1.4.2: Crea una versin alternativa del ejercicio 1.3.3, leyendo los datos a un array en vez de
trabajar byte a byte: un programa que extraiga el contenido de un fichero binario, volcando a
un fichero de texto todo lo que sean caracteres imprimibles (basta con que sean desde la A
hasta la Z, junto con el espacio en blanco).

1.4.3: Abre una imagen en formato BMP y comprueba si est comprimida, mirando el valor del
byte en la posicin 30 (empezando a contar desde 0). Si ese valor es un 0 (que es lo habitual),
indicar que el fichero no est comprimido. Debers leer toda la cabecera (los primeros 54
bytes) con una sola orden.

Acceso a datos, Tema 1 (versin 1.00) - Pgina 10


1.5. Serializacin
Guardar un objeto en un fichero no es mucho ms difcil que guardar datos nativos. Por una
parte, la clase correspondiente deber implementar la interfaz Serializable. Por otra parte,
los ficheros debern ser de tipo ObjectOutputStream y ObjectInputStream, como muestra el
siguiente ejemplo:

import java.io.Serializable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.io.FileNotFoundException;

class Ciudad implements Serializable {

protected String codigo;


protected String nombre;

// Constructor
public Ciudad(String cod, String nom) {
codigo = cod;
nombre = nom;
}

// Mtodo adicional
public void escribir() {
System.out.println(codigo + ": " + nombre);
}
}

public class Serializar {


public static void main( String[] args )
throws FileNotFoundException, IOException {

File fichero = new File("ciudades.dat");


FileOutputStream ficheroSalida =
new FileOutputStream(fichero);
ObjectOutputStream ficheroObjetos =
new ObjectOutputStream(ficheroSalida);

Ciudad c = new Ciudad("A", "Alicante");


ficheroObjetos.writeObject(c);

c = new Ciudad("Gr", "Granada");


ficheroObjetos.writeObject(c);

ficheroObjetos.close();
}
}

Para leer es similar, pero empleando el mtodo readObject de la clase ObjectInputStream e


interceptando (o lanzando) la excepcin ClassNotFoundException:

import java.io.*;
import java.lang.ClassNotFoundException;

Acceso a datos, Tema 1 (versin 1.00) - Pgina 11


class Ciudad implements Serializable {

protected String codigo;


protected String nombre;

// Constructor
public Ciudad(String cod, String nom) {
codigo = cod;
nombre = nom;
}

// Mtodo adicional
public void escribir() {
System.out.println(codigo + ": " + nombre);
}
}

public class DeSerializar {


public static void main( String[] args )
throws FileNotFoundException, IOException,
ClassNotFoundException {

File fichero = new File("ciudades.dat");


FileInputStream ficheroSalida =
new FileInputStream(fichero);
ObjectInputStream ficheroObjetos =
new ObjectInputStream(ficheroSalida);

Ciudad c = (Ciudad) ficheroObjetos.readObject();


c.escribir();

c = (Ciudad) ficheroObjetos.readObject();
c.escribir();

ficheroObjetos.close();
}
}

Ejercicios propuestos

1.5.1: Crea una clase Persona, con datos nombre, e-mail, ao de nacimiento. Haz un programa
que cree tres objetos de tipo persona y los guarde en un fichero llamado personas.dat.

1.5.2: Haz un programa que muestre los datos de las tres personas que se haban guardado en
el fichero personas.dat.

1.5.3: Ampliando el esqueleto de los dos ejercicios anteriores, crea una agenda, que permita
al usuario introducir datos de personas y buscar entre los datos existentes. Cada vez que se
aade un nuevo dato, todos ellos se guardarn en fichero. Cuando se vuelva a lanzar el
programa, los datos existentes se cargarn desde el fichero.

Acceso a datos, Tema 1 (versin 1.00) - Pgina 12


1.6. Leer ficheros XML
Como probablemente sabrs, el formato XML (eXtensible Markup Language, lenguaje de
marcas extensible) es un formato de texto delimitado por etiquetas, especialmente habitual
para intercambio de informacin entre sistemas.

Existen varias alternativas para manipular ficheros XML desde Java.

La primera forma, que no desarrollaremos, sera hacerlo de manera artesanal,


abriendo un fichero de texto y analizando cada elemento que se va leyendo, para ver
dnde empieza cada etiqueta, dnde termina y cual es el valor del elemento
correspondiente.
Una alternativa ms eficiente es usar SAX (Simple API for XML), que permite leer un
fichero de forma secuencial (de principio a fin, sin conservar en memoria informacin
sobre los datos que se haban ledo anteriormente).
Una tercera alternativa, que puede resultar ms til en muchos casos pero que
consume mucha ms memoria, es almacenar todo el rbol del documento (lo que se
suele llamar el DOM, Document Object Model).
Pero existen ms posibilidades, que no veremos. Por ejemplo, existen herramientas
que son capaces de generar una estructura de clases Java nativas con la ayuda de
hojas de estilo XSL.

Para los ejemplos que siguen, vamos a partir de un fichero XML que tenga el siguiente
contenido:

<asignaturas>
<asignatura id="ad">
<nombre>Acceso a Datos</nombre>
<cicloFormativo>D.A.M.</cicloFormativo>
<curso>Segundo</curso>
<profesor>Nacho</profesor>
</asignatura>
<asignatura id="int">
<nombre>Interfaces</nombre>
<cicloFormativo>D.A.M.</cicloFormativo>
<curso>Segundo</curso>
<profesor>Antonio</profesor>
</asignatura>
<asignatura id="lm">
<nombre>Lenguajes de marcas</nombre>
<cicloFormativo>ASIR</cicloFormativo>
<curso>Primero</curso>
<profesor>Fernando</profesor>
</asignatura>
</asignaturas>

1.6.1. SAX
SAX slo permite lectura secuencial del fichero, de principio a fin, no se encarga de almacenar
toda la estructura de datos en memoria. Por eso , ser razonable emplearlo para anlisis
sencillos, en los que se desee volcar un fichero XML a otro tipo de fichero de datos o a una
estructura dinmica en memoria creada por nosotros mismos.

Acceso a datos, Tema 1 (versin 1.00) - Pgina 13


La idea bsica de SAX es que ciertos eventos (por ejemplo, la apertura o el cierre de una
etiqueta XML) dispararn eventos que nuestro programa puede interceptar.

Los pasos sern:

Crear un objeto de tipo SAXParserFactory.


A partir de l, crear un SAXParser.
Crear un manejador de eventos, un DefaultHandler y crear el contenido para los
mtodos startElement (apertura de etiqueta), characters (recepcin del texto
contenido entre la apertura y el cierre de una etiqueta) y endElement (cierre de
etiqueta).
Llamar al mtodo parse del parser, indicndole el fichero que debe analizar y el
manejador de eventos que ha de emplear.

As, un ejemplo del uso de SAX para recorrer el fichero anterior podra ser:

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

class ReadXml extends DefaultHandler{

public void procesarXml(){


try {
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
SAXParser saxParser = saxParserFactory.newSAXParser();
DefaultHandler manejadorEventos = new DefaultHandler(){

String etiquetaActual = "";


String contenido = "";

// Mtodo que se llama al encontrar inicio de etiqueta: '<'


public void startElement(String uri, String localName,
String qName, Attributes attributes)
throws SAXException {

// Si el nombre es "asignatura",
// empieza una nueva y mostramos su id
// Si no, memorizamos el nombre para mostrar despus
etiquetaActual = qName;
if (etiquetaActual == "asignatura")
System.out.println("Asignatura: " +
attributes.getValue("id"));
}

// Obtiene los datos entre '<' y '>'


public void characters(char ch[], int start, int length)
throws SAXException {

contenido = new String(ch, start, length);


}

// Llamado al encontrar un fin de etiqueta: '>'


public void endElement(String uri, String localName, String qName)
throws SAXException {

Acceso a datos, Tema 1 (versin 1.00) - Pgina 14


if (etiquetaActual != "") {
System.out.println(" " + etiquetaActual +
": "+ contenido);
etiquetaActual = "";
}
}
};

// Cuerpo de la funcin: trata de analizar el fichero deseado


// Llamar a startElement(), endElement() y character()
saxParser.parse("asignaturas.xml", manejadorEventos);
} catch (Exception e) {
e.printStackTrace();
}
}
}

public class Sax1 {


public static void main(String args[]) {
ReadXml ficheroXml = new ReadXml();
ficheroXml.procesarXml();
}
}

Ejercicios propuestos

1.6.1.1: Crea una fichero XML con datos de personas: nombre, e-mail, y edad. Haz un
programa que lea todo el contenido de ese fichero usando SAX y lo muestre en pantalla.

1.6.1.2: Haz un programa que muestre slo el nombre y el e-mail de las personas almacenadas
en el fichero XML anterior (pero no la edad).

1.6.1.3: Crea un programa que analice el fichero XML anterior, pero conserve slo los
nombres, que se guardarn en un ArrayList para finalmente mostrarse ordenados en pantalla.

1.6.2. DOM
Si se prefiere memorizar todo el rbol del documento, de modo que se pueda acceder a
cualquier dato en cualquier momento, la alternativa es emplear el DOM.

En este caso, los pasos sern:

Crear un objeto de tipo DocumentBuilderFactory.


A partir de l, crear un DocumentBuilder.
Crear tambin un Document y, con parse, indicarle el nombre del fichero que debe
analizar.
Obtener la lista de nodos con getElementsByTagName, que se podr recorrer con
for.
Si ese nodo tiene atributos, se podrn obtener con getAttribute(nombre).

Acceso a datos, Tema 1 (versin 1.00) - Pgina 15


Sus elementos estarn accesibles con getElementsByTagName(nombre)

Un fuente completo de ejemplo podra ser as:

import java.io.File;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.w3c.dom.Element;

public class Dom1 {


public static void main(String[] args){

try {
File inputFile = new File("asignaturas.xml");
DocumentBuilderFactory dbFactory
= DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(inputFile);
doc.getDocumentElement().normalize();

System.out.println("Elemento base : "


+ doc.getDocumentElement().getNodeName());
NodeList nList = doc.getElementsByTagName("asignatura");
System.out.println();

System.out.println("Recorriendo asignaturas...");
for (int temp = 0; temp < nList.getLength(); temp++) {
Node nNode = nList.item(temp);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) nNode;
System.out.println("Codigo: "
+ eElement.getAttribute("id"));
System.out.println("Nombre: "
+ eElement.getElementsByTagName("nombre")
.item(0).getTextContent());
System.out.println("Ciclo: "
+ eElement.getElementsByTagName("cicloFormativo")
.item(0).getTextContent());
System.out.println("Curso: "
+ eElement.getElementsByTagName("curso")
.item(0).getTextContent());
System.out.println("Profesor: "
+ eElement.getElementsByTagName("profesor")
.item(0).getTextContent());
System.out.println();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

Acceso a datos, Tema 1 (versin 1.00) - Pgina 16


Ejercicios propuestos

1.6.2.1: A partir del fichero XML sobre personas que has creado en el apartado 1.6.1.1, crea un
programa que lea todo su contenido usando DOM y lo muestre en pantalla.

1.6.2.2: Haz un programa que muestre slo el nombre y el e-mail de las personas almacenadas
en el fichero XML anterior (pero no la edad), empleando DOM.

1.6.2.3: Crea un programa que analice el fichero XML anterior usando DOM y que muestre slo
los nombres, ordenados alfabticamente.

1.6.2.4: Crea un programa que analice el fichero XML anterior y vuelque sus datos a un fichero
CSV (un fichero de texto en el que en cada lnea se guardar un registro, con sus campos
separados por comas; los datos de texto estarn entre comillas, pero los datos numricos no).
En ocasiones se incluyen los nombres de los campos en la primera fila, y eso deber hacer tu
programa, como este ejemplo:

"nombre","e-mail","edad"
"persona1","persona1@p.com",19
"persona2","persona2@p.com",21

1.6.2.5: Investiga la forma de crear un fichero XML usando DOM, o bien crea a mano
(empleando ficheros de texto convencionales) un fichero XML, que sea el resultado de
convertir el fichero CSV del ejercicio anterior. Puedes ignorar la primera lnea, porque los
campos sern fijos; eso s, ten en cuenta que puede existir alguna coma dentro del nombre de
la persona, como en apellido1, nombre1 y tu programa debe manejar esta circunstancia
correctamente.

1.6.2.6: Crea una versin mejorada del programa anterior, que sea capaz de convertir de un
fichero CSV (cuyos campos aparecern en la primera lnea) a un fichero XML. Para simplificar
un poco, supondremos que todos los datos, incluso los numricos, estarn encerrados entre
comillas, de modo que un fichero de prueba podra ser:

"nombre","e-mail","edad","ciudad"
"persona1","persona1@p.com","19","Alicante"
"apellido2, nombre2","persona2@p.com","21","San Vicente"

Acceso a datos, Tema 1 (versin 1.00) - Pgina 17


1.7. Complemento para el mundo real: Swing
Si te parecen feos los programas de consola, quiz te sean tiles unas nociones mnimas de
creacin de entornos grficos usando Swing, una biblioteca que est disponible desde Java 2.
Slo veremos cmo hacer entradas y salidas ligeramente ms vistosas, usando casillas de
texto, etiquetas de texto, botones y ventanas de aviso. Si necesitas ms, no te ser difcil
profundizar por tu cuenta a partir de ah.

Los programas que emplean Swing se pueden crear desde cero usando slo un editor de texto.
Aun as, herramientas ms avanzadas como NetBeans incluyen editores visuales, para ayudar
al menos a posicionar los elementos de forma ms sencilla, de modo que la parte visual del
programa se puede crear mucho ms rpido.

Los pasos para hacer una aplicacin sencilla que sumase dos nmeros seran:

En primer lugar, Netbeans 8.1 no permite crear directamente una aplicacin Swing, de modo
que se puede comenzar por crear un nuevo proyecto que sea un Aplicacin Java genrica, y
luego aadir un nuevo fichero (File / New), y escoger la categora de ventanas de interfaz de
usuario con Swing (Swing GUI Forms) y en concreto una ventana normal, que son las
llamadas JFrame Form:

Se abrir el programa en la vista de diseo (Design), que mostrar una ventana (Form)
vaca:

Acceso a datos, Tema 1 (versin 1.00) - Pgina 18


Ese nuevo fichero tendr su propio main, de modo que podramos eliminar por completo la
que inicialmente era la clase principal del proyecto.

Ahora podemos ir arrastrando componentes visuales desde la paleta del lado derecho
(Palette) a la ventana vaca, para componer la apariencia que deseamos:

Slo con eso ya se podra lanzar el proyecto, que debera mostrar todos sus componentes
pero stos todava tienen nombres poco amigables.

Se puede cambiar el texto de las etiquetas (Label) haciendo doble clic sobre ellas. Para las
casillas de texto (TextEdit) y los botones (Button), se deber hacer un clic para seleccionar el

Acceso a datos, Tema 1 (versin 1.00) - Pgina 19


componente y luego cambiar su atributo text en la lista de propiedades que aparece en la
parte derecha de la pantalla:

Con eso ya se podr lanzar un programa ms amigable pero cuyo botn Sumar todava no
responde a los clics:

Para solucionarlo, habr que hacer doble clic en el botn (dentro del diseador visual) y se
crear automticamente un mtodo ActionPerformed, que todava estar vaco:

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {

);
}

En nuestro caso, queremos convertir de cadena a nmeros los valores de las dos casillas de
texto (con algo como Integer. parseInt( jTextField1. getText())), sumarlos y mostrar el
resultado en una ventana de dilogo (que, en su forma ms sencilla, se lanzaran con
JOptionPane.showMessageDialog (que necesitar su correspondiente import) al que se le
indican el Frame al que pertenece (this) y el texto a mostrar:

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {


JOptionPane.showMessageDialog(this, "La suma es "+
(Integer.parseInt(jTextField1.getText()) +

Acceso a datos, Tema 1 (versin 1.00) - Pgina 20


Integer.parseInt(jTextField2.getText()))
);
}

El programa resultante debera funcionar correctamente. Incluso se podra llevar a un


ordenador con otro sistema operativo, que no tenga NetBeans (quiz eliminando la orden
package), recompilar desde lnea de comandos o desde Geany y lanzar, con el mismo
resultado:

El cdigo fuente del programa, en el que apenas hemos tecleado tres lneas de cdigo y el
resto ha sido autogenerado, sera algo como:

package swing01;

import javax.swing.JOptionPane;

public class Swing01 extends javax.swing.JFrame {

/**
* Creates new form
*/
public Swing01() {
initComponents();
}

/**
* This method is called from within the constructor to initialize the
form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {

Acceso a datos, Tema 1 (versin 1.00) - Pgina 21


jLabel1 = new javax.swing.JLabel();
jButton1 = new javax.swing.JButton();
jLabel2 = new javax.swing.JLabel();
jTextField1 = new javax.swing.JTextField();
jTextField2 = new javax.swing.JTextField();

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

jLabel1.setText("Segundo nmero");

jButton1.setText("Sumar");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});

jLabel2.setText("Primer nmero");

javax.swing.GroupLayout layout = new


javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(

layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING,
layout.createSequentialGroup()

.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILIN
G)
.addGroup(layout.createSequentialGroup()
.addGap(76, 76, 76)

.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING
)
.addComponent(jLabel1)
.addComponent(jLabel2))
.addGap(18, 18, 18)

.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING
)
.addComponent(jTextField2,
javax.swing.GroupLayout.DEFAULT_SIZE, 80, Short.MAX_VALUE)
.addComponent(jTextField1)))
.addGroup(layout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE,
Short.MAX_VALUE)
.addComponent(jButton1)))
.addGap(71, 71, 71))
);
layout.setVerticalGroup(

layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(18, 18, 18)

.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELIN
E)
.addComponent(jTextField1,
javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.PREFERRED_SIZE)

Acceso a datos, Tema 1 (versin 1.00) - Pgina 22


.addComponent(jLabel2))
.addGap(18, 18, 18)

.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELIN
E)
.addComponent(jTextField2,
javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel1))
.addGap(26, 26, 26)
.addComponent(jButton1)
.addContainerGap(38, Short.MAX_VALUE))
);

pack();
}// </editor-fold>

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {


JOptionPane.showMessageDialog(this, "La suma es "+
(Integer.parseInt(jTextField1.getText()) +
Integer.parseInt(jTextField2.getText()))
);
}

/**
* @param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting
code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the
default look and feel.
* For details see
http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info :
javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {

java.util.logging.Logger.getLogger(Swing01.class.getName()).log(java.util.logg
ing.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {

java.util.logging.Logger.getLogger(Swing01.class.getName()).log(java.util.logg
ing.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {

java.util.logging.Logger.getLogger(Swing01.class.getName()).log(java.util.logg
ing.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {

java.util.logging.Logger.getLogger(Swing01.class.getName()).log(java.util.logg
ing.Level.SEVERE, null, ex);
}
//</editor-fold>

Acceso a datos, Tema 1 (versin 1.00) - Pgina 23


/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Swing01().setVisible(true);
}
});
}

// Variables declaration - do not modify


private javax.swing.JButton jButton1;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JTextField jTextField1;
private javax.swing.JTextField jTextField2;
// End of variables declaration
}

Ejercicios propuestos

1.7.1: Crea un programa con Swing, en el que el usuario introduzca en una casilla el nombre de
un fichero de texto. Al pulsar un botn, se leer todo el contenido del fichero y se mostrar en
una ventana de aviso la cantidad de lneas que contena.

1.7.2: Crea un programa con Swing, en el que el usuario introduzca en una casilla el nombre de
un fichero de texto y en otra casilla una palabra que desea buscar. Al pulsar un botn, se
analizar todo el contenido del fichero y se mostrar en una ventana de aviso la cantidad de
veces que esa palabra aparece en el fichero.

1.8. Para profundizar


Si quieres saber ms sobre ficheros, SAX o acceso al DOM, puedes consultar las siguientes
referencias oficiales:

Entrada y salida mediante ficheros: https://docs.oracle.com/javase/tutorial/essential/io/index.html


SAX: https://docs.oracle.com/javase/tutorial/jaxp/sax/index.html
XML DOM: https://docs.oracle.com/javase/tutorial/jaxp/dom/index.html
Para profundizar en Swing, tienes una serie de tutoriales oficiales en
https://docs.oracle.com/javase/tutorial/uiswing/

Acceso a datos, Tema 1 (versin 1.00) - Pgina 24

You might also like