Professional Documents
Culture Documents
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.
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;
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;
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.*;
import java.io.*;
import java.io.*;
class BufferedWriter1 {
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.
*****
*****
*****
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
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
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 {
try {
BufferedReader ficheroEntrada = new BufferedReader(
new FileReader(new File("ejemplo.txt")));
ficheroEntrada.close();
}
catch (IOException errorDeFichero) {
System.out.println(
"Ha habido problemas: " +
errorDeFichero.getMessage() );
}
System.out.println("Fin de la lectura.");
}
}
String linea=null;
while ((linea=ficheroEntrada.readLine()) != null) {
System.out.println(linea);
}
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.
import java.io.*;
class FileInputStream1
{
System.out.println("Contando \"a\"...");
int contador = 0;
try
{
FileInputStream ficheroEntrada2 =
new FileInputStream(new File("fichero.bin"));
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.
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.
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
{
try
{
InputStream ficheroEntrada3 = new FileInputStream(
new File("fichero.in"));
OutputStream ficheroSalida3 = new FileOutputStream(
new File("fichero2.out"));
System.out.println("Terminado!");
}
}
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.
import java.io.Serializable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
// Constructor
public Ciudad(String cod, String nom) {
codigo = cod;
nombre = nom;
}
// Mtodo adicional
public void escribir() {
System.out.println(codigo + ": " + nombre);
}
}
ficheroObjetos.close();
}
}
import java.io.*;
import java.lang.ClassNotFoundException;
// Constructor
public Ciudad(String cod, String nom) {
codigo = cod;
nombre = nom;
}
// Mtodo adicional
public void escribir() {
System.out.println(codigo + ": " + nombre);
}
}
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.
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.
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;
// 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"));
}
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.
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;
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("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();
}
}
}
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"
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:
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
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:
);
}
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:
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;
/**
* 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() {
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");
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)
.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>
/**
* @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>
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.