Tema 1 · Interpretación de Código
Explicación línea a línea de fragmentos de código Java de Tema 1, pensada para repasar qué hace cada instrucción. Usa el menú lateral para saltar directamente a cada código.
Página 2: Formas de declarar un fichero
No es un programa completo, sino varios ejemplos sueltos que muestran las
distintas formas de crear un objeto File: con la ruta completa en
un único String, o separando el directorio del nombre de fichero.
//Windows
File fichero1 = new File( "C:\\EJERCICIOS\\UNI1\\ejemplo1.txt");
//Linux
File fichero1 = new File( "/home/ejercicios/uni1/ejemplo1.txt");
String directorio= "C:/EJERCICIOS/UNI1";
File fichero2 = new File(directorio, "ejemplo2.txt");
File direc = new File(directorio);
Explicación línea a línea
-
1
File fichero1 = new File("C:\\EJERCICIOS\\UNI1\\ejemplo1.txt");Primer constructor: la ruta completa (directorio + fichero) en un único
String. En Windows el separador es\, y hay que escribirlo doble (\\) porque la barra invertida es un carácter especial en Java. -
2
File fichero1 = new File("/home/ejercicios/uni1/ejemplo1.txt");La misma idea, pero en Linux, donde el separador de rutas es
/y no hace falta escaparlo. -
3
String directorio= "C:/EJERCICIOS/UNI1";Se guarda solo la ruta del directorio en una variable de texto aparte, para reutilizarla.
-
4
File fichero2 = new File(directorio, "ejemplo2.txt");Segundo constructor: se pasan dos
Stringpor separado, el directorio y el nombre del fichero;Filese encarga de unirlos correctamente. -
5
File direc = new File(directorio);Un objeto
Fileno tiene por qué apuntar a un fichero: aquí apunta a un directorio, usando ese mismoFilecomo base para el siguiente ejemplo (Página 3).
File tiene varios constructores para
representar la misma ruta de distintas formas (todo junto, o directorio y
nombre por separado), y puede representar tanto ficheros como directorios.
Página 3: VerDir
Antes del programa, la Página 3 muestra un tercer constructor de
File: File fichero3 = new File(direc, "ejemplo3.txt");
(un File de directorio + un nombre de fichero). Después, el programa
VerDir lista los ficheros del directorio actual y, para cada uno,
comprueba si es un fichero o un directorio.
import java.io.*;
public class VerDir {
public static void main(String[] args) {
String dir = ".";
File f = new File(dir);
String[] archivos = f.list();
System.out.printf("Ficheros en el directorio actual: %d %n",
archivos.length);
for (int i = 0; i < archivos.length; i++) {
File f2 = new File(f, archivos[i]);
System.out.printf("Nombre: %s, es fichero?: %b, es directorio?: %b %n", archivos[i], f2.isFile(),f2.isDirectory());
}
}
}
Explicación línea a línea
-
1
String dir = ".";El punto
"."es un atajo que representa el directorio actual (desde donde se ejecuta el programa). -
2
File f = new File(dir);Se crea un
Fileque apunta a ese directorio actual. -
3
String[] archivos = f.list();list()devuelve un array deStringcon los nombres de todo lo que hay dentro de ese directorio (ficheros y subdirectorios). -
4
System.out.printf("Ficheros en el directorio actual: %d %n", archivos.length);Se imprime cuántos elementos se han encontrado, usando
printfcon%d(número entero) y%n(salto de línea). -
5
for (int i = 0; i < archivos.length; i++) {Se recorre cada nombre devuelto por
list(). -
6
File f2 = new File(f, archivos[i]);Se crea un nuevo
Filecombinando el directoriofcon cada nombre, para poder consultar sus propiedades individualmente (mismo constructor visto en la Página 3, directorio + nombre). -
7
System.out.printf("Nombre: %s, es fichero?: %b, es directorio?: %b %n", ...);Se imprime el nombre junto con el resultado de
isFile()eisDirectory(), usando%spara texto y%bpara booleanos.
Resultado Mostrado por Terminal (impreso en la Página 4)
list() para obtener los
nombres del directorio actual y, por cada uno, crea un File aparte
para poder preguntarle si es un fichero o un directorio.
Página 4: VerInf
Antes del programa, la Página 4 muestra dos variantes rápidas del ejemplo
VerDir: apuntar a otro directorio fijo
(File f = new File("d:\\db");) o a uno indicado por el usuario al
ejecutar el programa (String dir=args[0];). Después, el programa
VerInf muestra información detallada de un fichero concreto
usando varios métodos de File.
import java.io.*;
public class VerInf {
public static void main(String[] args) {
System.out.println("INFORMACIÓN SOBRE EL FICHERO:");
File f = new File("D:\\ADAT\\UNI1\\VerInf.java");
if(f.exists()){
System.out.println("Nombre del fichero : "+f.getName());
System.out.println("Ruta : "+f.getPath());
System.out.println("Ruta absoluta : "+f.getAbsolutePath());
System.out.println("Se puede leer : "+f.canRead());
System.out.println("Se puede escribir : "+f.canWrite());
System.out.println("Tamaño : "+f.length());
System.out.println("Es un directorio : "+f.isDirectory());
System.out.println("Es un fichero : "+f.isFile());
System.out.println("Nombre del directorio padre: "+f.getParent());
}
}
}
Explicación línea a línea
-
1
System.out.println("INFORMACIÓN SOBRE EL FICHERO:");Se imprime una cabecera para el listado que viene a continuación.
-
2
File f = new File("D:\\ADAT\\UNI1\\VerInf.java");Se apunta a un fichero concreto mediante su ruta absoluta completa en Windows.
-
3
if(f.exists()){Antes de preguntar por sus propiedades, se comprueba que el fichero realmente existe; si no, no tendría sentido pedirle información.
-
4
f.getName()Devuelve solo el nombre del fichero, sin la ruta:
VerInf.java. -
5
f.getPath()Devuelve la ruta tal y como se usó para construir el
File. -
6
f.getAbsolutePath()Devuelve la ruta absoluta completa en el sistema de ficheros.
-
7
f.canRead() / f.canWrite()Indican si el fichero se puede leer y si se puede escribir, respectivamente (permisos).
-
8
f.length()Devuelve el tamaño del fichero, en bytes.
-
9
f.isDirectory() / f.isFile()Indican si lo que representa el objeto
Filees un directorio o un fichero normal. -
10
f.getParent()Devuelve el nombre del directorio que contiene a este fichero (su "padre").
Resultado Mostrado por Terminal (continúa en la Página 5)
File.
Página 5: CrearDir
El programa CrearDir crea un directorio nuevo, crea dos ficheros
vacíos dentro de él, renombra uno de esos ficheros y crea un tercer fichero
usando una ruta de texto directamente. Después se muestra cómo borrar un
fichero con delete().
import java.io.*;
public class CrearDir {
public static void main(String[] args) {
File d = new File("NUEVODIR");
File f1 = new File(d,"FICHERO1.TXT");
File f2 = new File(d,"FICHERO2.TXT");
d.mkdir();
try {
if (f1.createNewFile())
System.out.println("FICHERO1 creado correctamente...");
else
System.out.println("No se ha podido crear FICHERO1...");
if (f2.createNewFile())
System.out.println("FICHERO2 creado correctamente...");
else
System.out.println("No se ha podido crear FICHERO2...");
} catch (IOException ioe) {ioe.printStackTrace();}
f1.renameTo(new File(d,"FICHERO1NUEVO"));
try {
File f3 = new File("NUEVODIR/FICHERO3.TXT");
f3.createNewFile();
} catch (IOException ioe) {ioe.printStackTrace();}
}
}
Explicación línea a línea
-
1
File d = new File("NUEVODIR");Se declara un
Fileque representará el directorio que se va a crear. -
2
File f1 = new File(d,"FICHERO1.TXT"); / File f2 = new File(d,"FICHERO2.TXT");Se declaran dos ficheros dentro de ese directorio, usando el constructor
File(File, String). -
3
d.mkdir();Se crea físicamente el directorio
NUEVODIRen disco. Hasta este punto,dsolo era un objeto en memoria. -
4
if (f1.createNewFile()) ... else ...createNewFile()crea el fichero vacío y devuelvetruesi lo ha creado, ofalsesi ya existía; se avisa por pantalla del resultado. Se repite lo mismo paraf2. -
5
} catch (IOException ioe) {ioe.printStackTrace();}createNewFile()puede lanzarIOException, por eso va dentro de untry-catch; si algo falla, se imprime la traza del error. -
6
f1.renameTo(new File(d,"FICHERO1NUEVO"));Se renombra
FICHERO1.TXTaFICHERO1NUEVO, indicando el nuevo nombre como otro objetoFile. -
7
File f3 = new File("NUEVODIR/FICHERO3.TXT");Esta vez se apunta al nuevo fichero con una única ruta de texto (en vez de
File+String), mezclando/como separador dentro deNUEVODIR. -
8
f3.createNewFile();Se crea el tercer fichero, vacío, dentro de
NUEVODIR.
A continuación, el libro muestra cómo borrar el fichero f2 con
delete() (no se puede borrar NUEVODIR directamente
mientras contenga ficheros):
if(f2.delete())
System.out.println("Fichero borrado...");
else
System.out.println("No se ha podido borrar el fichero...");
mkdir() crea directorios,
createNewFile() crea ficheros vacíos, renameTo()
renombra y delete() borra; para borrar un directorio primero hay
que borrar (o mover) todo lo que contiene.
Página 12: LeerFichTexto
El programa LeerFichTexto lee, carácter a carácter, el propio
fichero fuente LeerFichTexto.java usando FileReader
(flujo de caracteres, en vez de bytes) y muestra cada carácter por pantalla.
import java.io.*;
public class LeerFichTexto {
public static void main(String[] args) throws IOException {
//declarar fichero
File fichero =
new File("C:\\EJERCICIOS\\UNI1\\LeerFichTexto.java");
//crear el flujo de entrada hacia el fichero
FileReader fic = new FileReader(fichero);
int i;
while ((i = fic.read()) != -1)
System.out.println((char) i);
fic.close();
}
}
Explicación línea a línea
-
1
public static void main(String[] args) throws IOException {Como este programa no usa
try-catch, delega el manejo de la excepción hacia fuera conthrows IOException. -
2
File fichero = new File("C:\\EJERCICIOS\\UNI1\\LeerFichTexto.java");Se apunta al propio fichero fuente del programa (ruta absoluta en Windows).
-
3
FileReader fic = new FileReader(fichero);Se crea el flujo de entrada de caracteres hacia el fichero (a diferencia de
FileInputStream, que trabaja con bytes). -
4
int i;Variable donde se guardará cada carácter leído (como número entero).
-
5
while ((i = fic.read()) != -1)read()lee un carácter y lo devuelve comoint; el bucle continúa mientras el valor devuelto sea distinto de-1(fin de fichero). -
6
System.out.println((char) i);Se convierte
iacharmediante un cast ((char) i) para mostrarlo como el carácter que realmente es, no como su valor numérico. -
7
fic.close();Se cierra el flujo de lectura.
El libro añade que, para leer de golpe bloques de 20 caracteres en vez de uno a
uno, se puede usar la variante de read() que recibe un array:
char b[]= new char[20];
while ((i = fic.read(b)) != -1) System.out.println(b);
read(b) rellena el array b con hasta 20 caracteres de
una vez y devuelve cuántos ha leído realmente (o -1 al llegar al
final); es más eficiente que leer carácter a carácter.
FileReader permite leer un fichero de
texto carácter a carácter (o por bloques), haciendo cast a
char para interpretarlo como texto y no como números.
Página 13: EscribirFichTexto
El programa EscribirFichTexto escribe, carácter a carácter, el
contenido de un String en un fichero de texto usando
FileWriter, y añade un * al final con
append().
import java.io.*;
public class EscribirFichTexto {
public static void main(String[] args) throws IOException {
File fichero = new
File("C:\\EJERCICIOS\\UNI1\\FichTexto.txt");
FileWriter fic = new FileWriter(fichero);
String cadena ="Esto es una prueba con FileWriter";
char[] cad = cadena.toCharArray();
for(int i=0; i<cad.length; i++)
fic.write(cad[i]);
fic.append('*');
fic.close();
}
}
Explicación línea a línea
-
1
File fichero = new File("C:\\EJERCICIOS\\UNI1\\FichTexto.txt");Se apunta al fichero de texto que se va a crear/sobrescribir.
-
2
FileWriter fic = new FileWriter(fichero);Se crea el flujo de salida de caracteres; si el fichero ya existía, su contenido anterior se borra (por defecto no se añade al final).
-
3
String cadena ="Esto es una prueba con FileWriter";Se declara el texto que se quiere escribir en el fichero.
-
4
char[] cad = cadena.toCharArray();Se convierte el
Stringen un array dechar, para poder recorrerlo y escribirlo carácter a carácter. -
5
for(int i=0; i<cad.length; i++) fic.write(cad[i]);Se recorre el array y se escribe cada carácter, uno a uno, con
write(int). -
6
fic.append('*');append()añade un carácter (o texto) al final de lo ya escrito, sin sobrescribir nada. -
7
fic.close();Se cierra el flujo, asegurando que todo lo escrito queda guardado en el fichero.
El libro añade que, en vez de escribir carácter a carácter, se puede escribir un
array entero de golpe con fic.write(cad), y muestra un ejemplo
escribiendo varias cadenas seguidas desde un array de String
(continúa en la Página 14):
String prov[] =
{"Albacete","Avila","Badajoz","Cáceres","Huelva","Jaén",
"Madrid","Segovia","Soria","Toledo","Valladolid","Zamora"};
for(int i=0; i<prov.length; i++) fic.write(prov[i]);
Aquí write(String) escribe cada provincia completa de una vez; como
no se añade ningún salto de línea entre una y otra, quedarán todas pegadas
seguidas en el fichero.
FileWriter permite escribir texto
carácter a carácter, un array de caracteres de golpe, o directamente un
String completo con write(String); append()
añade contenido sin borrar lo anterior.
Página 14: LeerFichTextoBuf
Antes del programa, el libro muestra que FileWriter fic = new
FileWriter(fichero, true); permite añadir al final de un
fichero en vez de borrar su contenido (segundo parámetro true), y que
BufferedReader se construye envolviendo un FileReader.
El programa LeerFichTextoBuf usa esa combinación para leer un
fichero línea a línea (en vez de carácter a carácter).
import java.io.*;
public class LeerFichTextoBuf {
public static void main(String[] args) {
try{
BufferedReader fichero = new BufferedReader(
new FileReader("LeerFichTexto.java"));
String linea;
while((linea = fichero.readLine()) !=null)
System.out.println(linea);
fichero.close();
}
catch (FileNotFoundException fn ){
System.out.println("No se encuentra el fichero");}
catch (IOException io) {
System.out.println("Error de E/S ");}
}
}
Explicación línea a línea
-
1
try{Aquí todo el trabajo con ficheros se agrupa dentro de un
try-catch, en vez de usarthrows IOExceptionenmain. -
2
BufferedReader fichero = new BufferedReader(new FileReader("LeerFichTexto.java"));Se envuelve un
FileReadercon unBufferedReader, que añade un búfer de lectura eficiente y, sobre todo, el métodoreadLine()(leer líneas completas), algo queFileReaderno tiene por sí solo. -
3
String linea;Variable donde se guardará cada línea leída.
-
4
while((linea = fichero.readLine()) !=null)readLine()lee una línea completa y la devuelve, o devuelvenullal llegar al final del fichero; el bucle continúa mientras haya líneas. -
5
System.out.println(linea);Se imprime la línea leída tal cual, sin necesidad de cast (ya es un
String, no un número como conread()). -
6
fichero.close();Se cierra el flujo dentro del propio bloque
try, tras terminar de leer. -
7
catch (FileNotFoundException fn ){ ... } catch (IOException io) { ... }Se capturan por separado dos posibles errores: que el fichero no exista (
FileNotFoundException), o cualquier otro error de entrada/salida (IOException), mostrando un mensaje distinto para cada caso.
BufferedReader envuelve a
FileReader para poder leer el fichero línea a línea con
readLine(), en vez de carácter a carácter; el fin de fichero se
detecta aquí con null, no con -1.
Páginas 14-15: EscribirFichTextoBuf
Antes del programa, el libro muestra que BufferedWriter se
construye envolviendo un FileWriter, igual que pasaba con
BufferedReader. El programa EscribirFichTextoBuf
escribe 10 líneas de texto en un fichero, saltando de línea después de cada una
con newLine().
import java.io.*;
public class EscribirFichTextoBuf {
public static void main(String[] args) {
try{
BufferedWriter fichero = new BufferedWriter
(new FileWriter("FichTexto.txt"));
for (int i=1; i<11; i++){
fichero.write("Fila numero: "+i);
fichero.newLine();
}
fichero.close();
}
catch (FileNotFoundException fn ){
System.out.println("No se encuentra el fichero");}
catch (IOException io) {
System.out.println("Error de E/S ");}
}
}
Explicación línea a línea
-
1
BufferedWriter fichero = new BufferedWriter(new FileWriter("FichTexto.txt"));Se envuelve un
FileWritercon unBufferedWriter, que añade un búfer para escribir caracteres de forma eficiente y aporta el métodonewLine(). -
2
for (int i=1; i<11; i++){Bucle que recorre los números del 1 al 10 (10 vueltas en total).
-
3
fichero.write("Fila numero: "+i);Se escribe el texto
"Fila numero: "concatenado con el número de la vuelta actual. -
4
fichero.newLine();Se escribe un salto de línea, para que la siguiente fila quede en una línea nueva.
-
5
fichero.close();Se cierra el flujo una vez escritas las 10 líneas.
BufferedWriter añade a
FileWriter un búfer eficiente y el método newLine()
para no tener que escribir el salto de línea a mano.
Página 15: Reescritura con PrintWriter
El libro presenta PrintWriter (también deriva de Writer)
como alternativa más cómoda: tiene los métodos print() y
println(), igual que System.out, y
println() añade el salto de línea automáticamente. Se construye
envolviendo un FileWriter. Con esto, el ejemplo de
EscribirFichTextoBuf se puede reescribir así, mucho más corto:
PrintWriter fichero = new PrintWriter
(new FileWriter("FichTexto.txt"));
for(int i=1; i<11; i++)
fichero.println("Fila numero: "+i);
fichero.close();
Explicación línea a línea
-
1
PrintWriter fichero = new PrintWriter(new FileWriter("FichTexto.txt"));Se envuelve un
FileWritercon unPrintWriter, que aporta los métodosprint()yprintln(). -
2
for(int i=1; i<11; i++)Mismo bucle de antes: del 1 al 10.
-
3
fichero.println("Fila numero: "+i);Se escribe la línea y se salta de línea en la misma instrucción; ya no hace falta llamar a
newLine()por separado como conBufferedWriter. -
4
fichero.close();Se cierra el flujo, igual que en los ejemplos anteriores.
PrintWriter hace lo mismo que
BufferedWriter + newLine(), pero en menos código,
reutilizando los métodos print()/println() que ya se
conocen de System.out.
Página 16: EscribirFichBytes
Este programa escribe los números del 1 al 99 en un fichero byte a byte
usando FileOutputStream, y a continuación vuelve a leer ese
mismo fichero con FileInputStream, mostrando cada valor leído
por consola.
import java.io.*;
public class EscribirFichBytes {
public static void main(String[] args) throws IOException {
File fichero = new File("c:\\...");
FileOutputStream fileout = new FileOutputStream(fichero);
FileInputStream filein = new FileInputStream(fichero);
int i;
for (i = 1; i < 100; i++) {
fileout.write(i);
}
fileout.close();
while ((i = filein.read()) != -1) {
System.out.println(i);
}
filein.close();
}
}
Explicación línea a línea
-
1
import java.io.*;Se importan todos los paquetes de
java.io, donde están las clases para trabajar con ficheros y flujos de entrada/salida (File,FileOutputStream,FileInputStream...). -
2
public class EscribirFichBytes {Se declara una clase pública llamada
EscribirFichBytes. -
3
public static void main(String[] args) throws IOException {Se declara el método
main: es estático, no devuelve nada (void) y recibe como argumento un array deStringllamadoargs. Además, puede lanzar una excepción de tipoIOException. -
4
File fichero = new File("c:\...");Se crea una variable
ficherode tipoFile, indicando como argumento la ruta del archivo. -
5
FileOutputStream fileout = new FileOutputStream(fichero);Se crea la variable
fileoutde tipoFileOutputStream, asignándole un nuevo objeto que recibeficherocomo argumento: este flujo permitirá escribir bytes en el archivo. -
6
FileInputStream filein = new FileInputStream(fichero);Se crea la variable
fileinde tipoFileInputStream, asignándole un nuevo objeto que recibeficherocomo argumento: este flujo permitirá leer bytes del archivo. -
7
int i;Se declara una variable entera llamada
i, que se reutilizará más abajo como contador y como valor leído. -
8
for (i = 1; i < 100; i++) {Se inicia un bucle
foren el queiempieza en 1 y se incrementa de 1 en 1 mientras sea menor que 100 (es decir, recorre del 1 al 99). -
9
fileout.write(i);En cada vuelta del bucle se escribe el valor de
identro del flujo de salidafileout, es decir, se guarda ese byte en el fichero. -
10
fileout.close();Se cierra el flujo de salida
fileoutuna vez terminado el bucle, liberando el recurso y asegurando que todo lo escrito quede guardado en el fichero. -
11
while ((i = filein.read()) != -1) {Se inicia un bucle
whileen el que aise le asigna lo que devuelvefilein.read()(el siguiente byte leído). El bucle continúa mientras ese valor sea distinto de-1, que es lo que devuelveread()al llegar al final del fichero. -
12
System.out.println(i);Se muestra por pantalla el valor almacenado en
i, es decir, cada byte leído del fichero. -
13
filein.close();Se cierra el flujo de entrada
filein, liberando el recurso una vez terminada la lectura.
FileOutputStream y FileInputStream para escribir y leer
datos byte a byte en Java.
Página 17: EscribirFichData
Aquí en vez de FileOutputStream a secas (que solo escribe bytes
sueltos), se envuelve ese flujo con un DataOutputStream, que añade
métodos como writeUTF() y writeInt() para escribir
directamente tipos de datos primitivos (cadenas, enteros...) en el fichero
binario FichData.dat.
import java.io.*;
public class EscribirFichData {
public static void main(String[] args) throws IOException {
File fichero = new File("FichData.dat");
FileOutputStream fileout = new FileOutputStream(fichero);
DataOutputStream dataOS = new DataOutputStream(fileout);
String nombres[] =
{"Ana","Luis Miguel","Alicia","Pedro","Manuel",
"Andrés", "Julio","Antonio","María Jesús"};
int edades[] = {14,15,13,15,16,12,16,14,13};
for (int i=0; i<edades.length; i++){
dataOS.writeUTF(nombres[i]);
dataOS.writeInt(edades[i]);
}
dataOS.close();
}
}
Explicación línea a línea
-
1
import java.io.*;Se importan todos los paquetes de
java.io. -
2
public class EscribirFichData {Se declara una clase pública llamada
EscribirFichData. -
3
public static void main(String[] args) throws IOException {Se declara el método
main, estático, sin retorno y que puede lanzarIOException. -
4
File fichero = new File("FichData.dat");Se crea el objeto
Fileque apunta al ficheroFichData.dat(ruta relativa). -
5
FileOutputStream fileout = new FileOutputStream(fichero);Se crea un flujo de salida de bytes
fileoutenlazado al fichero. -
6
DataOutputStream dataOS = new DataOutputStream(fileout);Se envuelve
fileoutcon unDataOutputStream, que permite escribir tipos de datos primitivos (no solo bytes sueltos) mediante métodos comowriteUTF()ywriteInt(). -
7
String nombres[] = {"Ana", "Luis Miguel", ...};Se declara y se rellena un array de
Stringcon los nombres de las personas. -
8
int edades[] = {14,15,13,15,16,12,16,14,13};Se declara y se rellena un array de
intcon las edades, en el mismo orden que el array de nombres (posición a posición forman parejas). -
9
for (int i=0; i<edades.length; i++){Se inicia un bucle
forque recorre todas las posiciones del arrayedades(y, por tanto, también las del arraynombres, que tiene la misma longitud). -
10
dataOS.writeUTF(nombres[i]);Se escribe en el fichero el nombre de la posición
i, codificado como texto UTF. -
11
dataOS.writeInt(edades[i]);Justo después, se escribe la edad de la posición
icomo número entero. Nombre y edad quedan guardados seguidos, en parejas. -
12
dataOS.close();Se cierra el flujo
dataOS, lo que fuerza a que todo lo escrito quede realmente guardado enFichData.dat.
FichData.dat usando
DataOutputStream, que sabe escribir tipos primitivos directamente
(a diferencia de FileOutputStream, que solo trabaja con bytes sueltos).
Es imprescindible recordar el orden en que se escribe cada dato,
porque habrá que leerlo exactamente en ese mismo orden (ver Página 18).
Página 18: LeerFichData
Este programa lee de vuelta el fichero FichData.dat generado en la
Página 17, usando DataInputStream para recuperar los datos con
readUTF() y readInt(), respetando el mismo orden en el
que se escribieron: primero el nombre y luego la edad.
import java.io.*;
public class LeerFichData {
public static void main(String[] args) throws IOException {
File fichero = new File("FichData.dat");
FileInputStream filein = new FileInputStream(fichero);
DataInputStream dataIS = new DataInputStream(filein);
String n;
int e;
try {
while (true) {
n = dataIS.readUTF();
e = dataIS.readInt();
System.out.println("Nombre: " + n + ", edad: " + e);
}
}catch (EOFException eo) {}
dataIS.close();
}
}
Explicación línea a línea
-
1
import java.io.*;Se importan todos los paquetes de
java.io. -
2
public class LeerFichData {Se declara una clase pública llamada
LeerFichData. -
3
public static void main(String[] args) throws IOException {Se declara el método
main, estático, sin retorno y que puede lanzarIOException. -
4
File fichero = new File("FichData.dat");Se apunta al mismo fichero que se generó en la Página 17.
-
5
FileInputStream filein = new FileInputStream(fichero);Se crea un flujo de entrada de bytes
fileinenlazado al fichero. -
6
DataInputStream dataIS = new DataInputStream(filein);Se envuelve
fileincon unDataInputStream, que permite leer tipos primitivos con métodos comoreadUTF()yreadInt(). -
7
String n; int e;Se declaran las variables
nye, que irán guardando, en cada vuelta del bucle, el nombre y la edad leídos. -
8
try {Se abre un bloque
tryporque no se sabe de antemano cuántos registros hay: se leerá hasta que salte una excepción al llegar al final del fichero. -
9
while (true) {Bucle infinito: seguirá leyendo registros hasta que lo interrumpa la excepción de fin de fichero.
-
10
n = dataIS.readUTF();Se lee el siguiente dato del fichero como texto UTF y se guarda en
n(el nombre). -
11
e = dataIS.readInt();A continuación se lee el siguiente dato como número entero y se guarda en
e(la edad). Debe leerse justo después del nombre, porque así se escribió. -
12
System.out.println("Nombre: " + n + ", edad: " + e);Se muestra por pantalla la pareja nombre-edad que se acaba de leer.
-
13
} catch (EOFException eo) {}Cuando ya no quedan más datos,
readUTF()/readInt()lanzanEOFException(fin de fichero); se captura con un bloque vacío, que simplemente corta el bucle sin mostrar ningún error. -
14
dataIS.close();Se cierra el flujo de entrada una vez terminada la lectura.
Resultado Mostrado por Terminal
EOFException) como forma "normal" de detectar que se ha
llegado al final del fichero, ya que DataInputStream no tiene un
equivalente directo al -1 de read() para tipos compuestos.
Páginas 19-20: Persona y EscribirFichObject
La serialización convierte un objeto en una secuencia de bytes que luego se puede restaurar. La clase debe implementar Serializable. Se escribe con ObjectOutputStream (sobre un FileOutputStream) y writeObject().
import java.io.Serializable;
public class Persona implements Serializable {
private String nombre;
private int edad;
public Persona(String nombre, int edad) { this.nombre = nombre; this.edad = edad; }
public Persona() { this.nombre = null; }
// set/get de nombre y edad ...
}
import java.io.*;
public class EscribirFichObject {
public static void main(String[] args) throws IOException {
Persona persona;
File fichero = new File("FichPersona.dat");
FileOutputStream fileout = new FileOutputStream(fichero);
ObjectOutputStream dataOS = new ObjectOutputStream(fileout);
String nombres[] = {"Ana","Luis Miguel","Alicia","Pedro","Manuel","Andrés","Julio","Antonio","María Jesús"};
int edades[] = {14,15,13,15,16,12,16,14,13};
for (int i=0; i<edades.length; i++) {
persona = new Persona(nombres[i], edades[i]);
dataOS.writeObject(persona);
}
dataOS.close();
}
}Explicación línea a línea
- 1
public class Persona implements SerializableImplementar
Serializable(interfaz sin métodos) es lo que permite guardar objetos de esta clase en un fichero binario. Tiene dos atributos privados, dos constructores y sus get/set. - 2
FileOutputStream fileout = new FileOutputStream(fichero);Flujo de bytes hacia el fichero en disco.
- 3
ObjectOutputStream dataOS = new ObjectOutputStream(fileout);Flujo que procesa objetos y los vuelca sobre el
FileOutputStream. Se puede abreviar anidando:new ObjectOutputStream(new FileOutputStream(fichero)). - 4
String nombres[] / int edades[]Dos arrays paralelos con los datos: la posición
ide cada uno corresponde a la misma persona. - 5
persona = new Persona(nombres[i], edades[i]);En cada vuelta se crea una
Personacon los datos de esa posición. - 6
dataOS.writeObject(persona);Escribe el objeto completo en el fichero.
- 7
dataOS.close();Cierra el flujo de salida.
Serializable, un ObjectOutputStream y writeObject().Páginas 20-21: LeerFichObject
Lee los objetos Persona con ObjectInputStream y readObject(). Como no se sabe cuántos objetos hay, se lee en un while(true) hasta que salta EOFException.
import java.io.*;
public class LeerFichObject {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Persona persona;
File fichero = new File("FichPersona.dat");
FileInputStream filein = new FileInputStream(fichero);
ObjectInputStream dataIS = new ObjectInputStream(filein);
try {
while (true) {
persona = (Persona) dataIS.readObject();
System.out.printf("Nombre: %s, edad: %d %n", persona.getNombre(), persona.getEdad());
}
} catch (EOFException eo) {
System.out.println("FIN DE LECTURA.");
}
dataIS.close();
}
}Explicación línea a línea
- 1
throws IOException, ClassNotFoundExceptionreadObject()puede lanzar ambas excepciones (ClassNotFoundExceptionsi no encuentra la clase del objeto leído). - 2
FileInputStream / ObjectInputStreamIgual que al escribir, pero de entrada: el
FileInputStreamlee bytes del fichero y elObjectInputStreamlos reconstruye como objetos. - 3
while (true) { ... }Bucle infinito: la salida no se controla con una condición, sino con la excepción del
catch. - 4
persona = (Persona) dataIS.readObject();readObject()devuelve unObject, por eso se hace cast aPersona. - 5
catch (EOFException eo)Al llegar al final del fichero se lanza
EOFException: es la forma de terminar la lectura y se avisa con "FIN DE LECTURA.". - 6
dataIS.close();Cierra el flujo de entrada.
EOFException (no con -1 ni null) y hay que hacer cast del resultado de readObject().Páginas 21-22: MiObjectOutputStream (añadir objetos)
Problema: cada new ObjectOutputStream(fichero) escribe una cabecera. Si se reabre el fichero para añadir, queda una segunda cabecera en medio y al leer salta StreamCorruptedException. Solución: heredar de ObjectOutputStream y anular writeStreamHeader().
public class MiObjectOutputStream extends ObjectOutputStream {
public MiObjectOutputStream(OutputStream out) throws IOException { super(out); }
protected MiObjectOutputStream() throws IOException, SecurityException { super(); }
// Redefinición del método de escribir la cabecera para que no haga nada.
protected void writeStreamHeader() throws IOException { }
}
File fichero = new File(nombrefichero);
ObjectOutputStream dataOS;
if (!fichero.exists()) {
FileOutputStream fileout = new FileOutputStream(fichero);
dataOS = new ObjectOutputStream(fileout);
} else {
dataOS = new MiObjectOutputStream(new FileOutputStream(fichero, true));
}Explicación línea a línea
- 1
public class MiObjectOutputStream extends ObjectOutputStreamClase propia que hereda todo el comportamiento de
ObjectOutputStream. - 2
MiObjectOutputStream(OutputStream out) { super(out); }Constructor que pasa el flujo al constructor de la clase padre. El segundo constructor (
protected, sin parámetros) llama asuper(). - 3
protected void writeStreamHeader() throws IOException { }Se sobrescribe el método que escribe la cabecera y se deja vacío: esta clase ya no añade cabecera.
- 4
if (!fichero.exists()) { ... }Si el fichero no existe (primera vez) se usa el
ObjectOutputStreamnormal, que sí escribe la cabecera necesaria. - 5
else { dataOS = new MiObjectOutputStream(new FileOutputStream(fichero, true)); }Si ya existe se usa la clase redefinida (sin cabecera) y
trueen elFileOutputStreampara añadir al final en vez de sobrescribir.
ObjectOutputStream; para añadir → MiObjectOutputStream con append = true, así el fichero conserva una única cabecera.Páginas 22-23: EscribirFichAleatorio
RandomAccessFile permite acceder a cualquier posición del fichero (no solo secuencialmente). Modos: "r" (solo lectura, el fichero debe existir) y "rw" (lectura y escritura, lo crea si no existe). Métodos clave: getFilePointer(), seek(pos), length() y skipBytes(n). Cada registro mide 36 bytes: id (int, 4) + apellido (10 chars × 2 = 20) + departamento (int, 4) + salario (double, 8).
import java.io.*;
public class EscribirFichAleatorio {
public static void main(String[] args) throws IOException {
File fichero = new File("AleatorioEmple.dat");
RandomAccessFile file = new RandomAccessFile(fichero, "rw");
String apellido[] = {"FERNANDEZ","GIL","LOPEZ","RAMOS","SEVILLA","CASILLA","REY"};
int dep[] = {10, 20, 10, 10, 30, 30, 20};
Double salario[] = {1000.45, 2400.60, 3000.0, 1500.56, 2200.0, 1435.87, 2000.0};
StringBuffer buffer = null;
int n = apellido.length;
for (int i = 0; i<n; i++) {
file.writeInt(i+1);
buffer = new StringBuffer(apellido[i]);
buffer.setLength(10);
file.writeChars(buffer.toString());
file.writeInt(dep[i]);
file.writeDouble(salario[i]);
}
file.close();
}
}Explicación línea a línea
- 1
RandomAccessFile file = new RandomAccessFile(fichero, "rw");Abre (o crea) el fichero en modo lectura/escritura. El puntero empieza en 0.
- 2
String apellido[] / int dep[] / Double salario[]Arrays paralelos con los datos de 7 empleados. No hace falta
seek()porque se escribe en orden y el puntero avanza solo. - 3
file.writeInt(i+1);Escribe el identificador (1, 2, 3...), 4 bytes. Se usa
i+1para que sea mayor que 0. - 4
buffer = new StringBuffer(apellido[i]); buffer.setLength(10);Se fuerza el apellido a exactamente 10 caracteres (rellena con espacios/nulos o recorta) para que todos los registros midan lo mismo.
- 5
file.writeChars(buffer.toString());Escribe los 10 caracteres a 2 bytes cada uno: 20 bytes.
- 6
file.writeInt(dep[i]); file.writeDouble(salario[i]);Escribe departamento (4 bytes) y salario (8 bytes). Total por registro: 4 + 20 + 4 + 8 = 36 bytes.
Página 24: LeerFichAleatorio
Recorre todos los registros del fichero anterior. Empieza en la posición 0 y suma 36 (tamaño del registro) para pasar al siguiente.
import java.io.*;
public class LeerFichAleatorio {
public static void main(String[] args) throws IOException {
File fichero = new File("AleatorioEmple.dat");
RandomAccessFile file = new RandomAccessFile(fichero, "r");
int id, dep, posicion;
Double salario;
char apellido[] = new char[10], aux;
posicion = 0;
for (;;) {
file.seek(posicion);
id = file.readInt();
for (int i = 0; i < apellido.length; i++) {
aux = file.readChar();
apellido[i] = aux;
}
String apellidos = new String(apellido);
dep = file.readInt();
salario = file.readDouble();
if (id > 0)
System.out.printf("ID: %s, Apellido: %s, Departamento: %d, Salario: %.2f %n",
id, apellidos.trim(), dep, salario);
posicion = posicion + 36;
if (file.getFilePointer() == file.length()) break;
}
file.close();
}
}Explicación línea a línea
- 1
new RandomAccessFile(fichero, "r");Modo solo lectura: el fichero debe existir y escribir lanzaría
IOException. - 2
char apellido[] = new char[10], aux; posicion = 0;Array de 10 caracteres para reconstruir el apellido;
posicionempieza en 0 (inicio del primer registro). - 3
for (;;) { file.seek(posicion); id = file.readInt();Bucle infinito. Cada vuelta coloca el puntero al inicio del registro y lee el id (4 bytes).
- 4
aux = file.readChar(); apellido[i] = aux;Lee uno a uno los 10 caracteres del apellido (20 bytes) y los guarda en el array.
- 5
String apellidos = new String(apellido);Convierte el array de
charenString. - 6
dep = file.readInt(); salario = file.readDouble();Lee departamento (4 bytes) y salario (8 bytes), que siguen justo después del apellido.
- 7
if (id > 0) System.out.printf(...)Solo imprime si el id es mayor que 0: así se saltan los registros borrados lógicamente (id = -1).
trim()quita los espacios de relleno y%.2fmuestra 2 decimales. - 8
posicion = posicion + 36;Avanza al siguiente registro (cada empleado ocupa 36 bytes).
- 9
if (file.getFilePointer() == file.length()) break;Si el puntero llegó al final del fichero, sale del bucle.
Resultado Mostrado por Terminal
seek(), leyendo los campos en el mismo orden y tipo en que se escribieron.Páginas 25-26: Consultar, añadir, insertar y modificar
Fragmentos sueltos (no programas completos) que usan la fórmula (id - 1) * 36 para saltar directamente a un registro sin recorrer el fichero.
// CONSULTAR el empleado 5
int identificador = 5;
posicion = (identificador - 1) * 36;
if (posicion >= file.length())
System.out.printf("ID: %d, NO EXISTE EMPLEADO...", identificador);
else {
file.seek(posicion);
id = file.readInt();
// obtener resto de los datos, como en el ejemplo anterior
}
// AÑADIR al final
long posicion = file.length();
file.seek(posicion);
// INSERTAR empleado con id 20
StringBuffer buffer = null;
String apellido = "GONZALEZ"; Double salario = 1230.87; int id = 20; int dep = 10;
long posicion = (id - 1) * 36;
file.seek(posicion);
file.writeInt(id);
buffer = new StringBuffer(apellido);
buffer.setLength(10);
file.writeChars(buffer.toString());
file.writeInt(dep);
file.writeDouble(salario);
file.close();
// MODIFICAR departamento y salario del empleado 4
int registro = 4;
long posicion = (registro - 1) * 36;
posicion = posicion + 4 + 20;
file.seek(posicion);
file.writeInt(40);
file.writeDouble(4000.87);Explicación línea a línea
- 1
posicion = (identificador - 1) * 36;Calcula dónde empieza el registro: el empleado 1 está en 0, el 2 en 36, el 5 en 144...
- 2
if (posicion >= file.length())Si la posición está fuera del fichero, ese empleado no existe; si no, se hace
seek()y se lee con normalidad. - 3
long posicion = file.length(); file.seek(posicion);Coloca el puntero al final para añadir registros después del último.
- 4
long posicion = (id - 1) * 36; ... writeInt / writeChars / writeInt / writeDoublePara insertar el id 20 se calcula su posición y se escriben los cuatro campos en el mismo orden de siempre (id, apellido de 10 chars, dep, salario).
- 5
posicion = posicion + 4 + 20;Para modificar, se salta el id (4 bytes) y el apellido (20 bytes) y se cae justo en el departamento.
- 6
file.writeInt(40); file.writeDouble(4000.87);Sobrescribe departamento (40) y salario (4000.87) del empleado 4. Aquí el fichero debe abrirse en modo
"rw".
La página 26 propone la Actividad 1.3 (consulta e inserción por línea de comandos) y la Actividad 1.4 (modificar el salario sumando un importe, y borrado lógico: id = -1, apellido = id borrado, dep y salario = 0, más un programa que liste los borrados). Después empieza el apartado 1.7 de ficheros XML, con este ejemplo de estructura:
<?xml version="1.0"?>
<Empleados>
<empleado>
<id>1</id>
<apellido>FERNANDEZ</apellido>
<dep>10</dep>
<salario>1000.45</salario>
</empleado>
<!-- más empleados ... -->
</Empleados>XML es un metalenguaje de marcas jerárquicas: una raíz (<Empleados>) que contiene elementos (<empleado>), cada uno con sus etiquetas de apertura y cierre. Se procesa con un parser: DOM (carga todo el árbol en memoria) o SAX (secuencial, por eventos).
(id - 1) * tamaño da la posición de cualquier registro, y sumando los tamaños de los campos anteriores (4 + 20) se llega a un campo concreto.