Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Manejo de Ficheros
Manejo de Ficheros
Caso práctico
Ya ha tenido unas reuniones con Juan y María, para saber cómo se trabaja en BK programación.
Aunque está haciendo el módulo de FCT en esta empresa, ya sabe que a veces tendrá que salir
a otras empresas acompañada de sus tutores para ver los requisitos de los sistemas que la
empresa tenga que informatizar y, en ocasiones, Antonio, quizás también se apunte para echar
una mano.
Ana está nerviosa, también ilusionada, y tiene muchas ganas de conocer de cerca la realidad de
lo que ha estudiado en clase.
Ahora verá el uso de los conocimientos adquiridos de diferentes módulos, y buscará respuestas
a posibles dudas que se vayan planteando.
En clase les habían explicado la importancia de los ficheros en el acceso a datos. -Es importante
repasar los conceptos -piensa Ana.
1.- Introducción.
Si estás estudiando este módulo, es probable que ya hayas estudiado el de programación, por
lo que no te serán desconocidos muchos conceptos que se tratan en este tema.
Ya sabes que cuando apagas el ordenador, los datos de la memoria RAM se pierden. Un
ordenador utiliza ficheros para guardar los datos. Piensa que los datos de las canciones que
oyes en mp3, las películas que ves en formato avi, o mp4, etc., están, al fin y al cabo,
almacenadas en ficheros, los cuales están grabados en un soporte como son los discos
duros, DVD, pendrives, etc.
Se llama a los datos que se guardan en ficheros datos persistentes, porque persisten más allá
de la ejecución de la aplicación que los trata. Los ordenadores almacenan los ficheros en
unidades de almacenamiento secundario como discos duros, discos ópticos, etc. En esta unidad
veremos, entre otras cosas, cómo hacer con Java las operaciones de crear, actualizar y procesar
ficheros.
A las operaciones, que constituyen un flujo de información del programa con el exterior, se les
conoce como Entrada/Salida (E/S).
Las operaciones de E/S en Java las proporciona el paquete estándar de la API de Java
denominado java.io que incorpora interfaces, clases y excepciones para acceder a todo tipo
de ficheros.
La librería java.io contiene las clases necesarias para gestionar las operaciones de entrada y
salida con Java. Estas clases de E/S las podemos agrupar fundamentalmente en:
Los datos persistentes perduran tras finalizar la ejecución de la aplicación que los trata.
Verdadero Falso
2.- Clases asociadas a las operaciones de gestión de
ficheros y directorios.
Caso práctico
Ana le comenta a Antonio -Por lo que nos han comentado, vamos a tener que utilizar bastante
los ficheros. ¿Cómo te manejas tú con ellos?
-Pues tan bien como tú -responde Antonio, -yo también estudié el módulo de Programación.
¿Es que no recuerdas que en el módulo estudiamos un tema sobre ficheros?
-Sí, pero es que, como había tantos métodos para listar, renombrar archivos, etc., ya casi no me
acuerdo; y eso que hace poco que lo estudiamos -contesta Ana.
Antonio intenta tranquilizar a Ana y le dice que no se preocupe, que en cuanto se les presente
la ocasión de tener que programar con ficheros, seguro que no tienen problema y refrescan los
conceptos que aprendieron en su día.
En efecto, tal y como dicen Ana y Antonio, hay bastantes métodos involucrados en las clases
que en Java nos permiten manipular ficheros y carpetas o directorios.
Vamos a ver la clase File que nos permite hacer unas cuantas operaciones con ficheros,
también veremos cómo filtrar ficheros, o sea, obtener aquellos con una característica
determinada, como puede ser que tengan la extensión .odt, o la que nos interese, y por último,
en este apartado también veremos cómo crear y eliminar ficheros y directorios.
2.1.- Clase File.
¿Para qué sirve esta clase, qué nos permite? La clase File proporciona una representación
abstracta de ficheros y directorios.
Las instancias de la clase File representan nombres de archivo, no los archivos en sí mismos.
El archivo correspondiente a un nombre puede ser que no exista, por esta razón habrá que
controlar las posibles excepciones.
Un objeto de clase File permite examinar el nombre del archivo, descomponerlo en su rama
de directorios o crear el archivo si no existe mediante el método createNewFile();
Para archivos que existen, a través del objeto File, un programa puede examinar los atributos
del archivo, cambiar su nombre, borrarlo o cambiar sus permisos. Dado un objeto File,
podemos hacer las siguientes operaciones con él:
Verdadero Falso
Para crear un objeto File, se puede utilizar cualquiera de los tres constructores siguientes:
- File(String directorioyfichero):
En Linux se utiliza como prefijo de una ruta absoluta “/". En Microsoft Windows, el prefijo de un
nombre de ruta consiste en la letra de la unidad seguida de “:” y, posiblemente, seguida por "\\"
si la ruta es absoluta. Para utilizar los separadores adecuados independientemente del sistema
que estemos utilizando es recomendable utilizar el campo separator.
El siguiente ejemplo muestra la lista de ficheros en el directorio actual. Se utiliza el método list()
que devuelve un array de Strings con los nombres de los ficheros y directorios contenidos en el
directorio asociado al objeto File. Para indicar que estamos en el directorio actual creamos un
objeto File y le pasamos el parámetro “.”:
import java.io.*;
El siguiente ejemplo muestra información del fichero o directorio seleccionado. En esta ocasión
se pasa la ruta utilizando los argumentos de main().
package file;
import java.io.*;
public class VerInf {
public static void main(String[] args) {
System.out.println("INFORMACIÓN SOBRE EL FICHERO:");
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());
}
else
System.out.println("El fichero o directorio no existe"); }
}
Por último, este ejemplo crea un directorio (de nombre NUEVODIR) en el directorio actual, a
continuación crea dos ficheros vacíos en dicho directorio y uno de ellos lo renombra. En este
caso para crear los ficheros se definen 2 parámetros en el objeto File: File(File directorio, String
nombrefich), en el primero indicamos el directorio donde se creará el fichero y en el segundo
indicamos el nombre del fichero:
import java.io.*;
public class CrearDir {
public static void main(String[] args) {
File d = new File("NUEVODIR"); //directorio que creo a partir del
actual
File f1 = new File(d,"FICHERO1.TXT");
File f2 = new File(d,"FICHERO2.TXT");
d.mkdir();//CREAR DIRECTORIO
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();}
}
}
Para borrar un fichero o directorio usamos el método delete(). Para borrar un directorio con
Java, tendremos que borrar cada uno de los ficheros y directorios que éste contenga. Al poder
almacenar otros directorios, se podría recorrer recursivamente el directorio para ir borrando
todos los ficheros.
Autoevaluación
Señala la opción correcta. Con la clase File podemos:
Crear directorios.
Renombrar un archivo.
3.- Flujos.
Caso práctico
Ana y Antonio saben que van a tener que ayudar a Juan y a María en labores de programación
de ficheros en Java. Así que, además, de la clase File, van a necesitar utilizar otros conceptos
relacionados con la entrada y salida: los flujos o streams. Ana recuerda que hay dos tipos de
flujos: flujos de caracteres y flujos de bytes.
Un programa en Java, que necesita realizar una operación de entrada/salida (en adelante E/S),
lo hace a través de un flujo o stream.
Las clases y métodos de E/S que necesitamos emplear son las mismas independientemente del
dispositivo con el que estemos actuando. Luego, el núcleo de Java sabrá si tiene que tratar con
el teclado, el monitor, un sistema de archivos o un socket de red; liberando al programador de
tener que saber con quién está interactuando.
Los archivos binarios guardan una representación de los datos en el archivo, es decir, cuando
guardamos texto no guardan el texto en sí, sino que guardan su representación en un código
llamado .
Las clases principales que heredan de OutputStream, para la escritura de ficheros binarios son:
En el siguiente ejemplo puedes ver cómo se crea un flujo de salida y otro de entrada a un archivo
binario mediante las clase FileInputStream y FileOutputStream. En primer lugar escribe los
bytes en un fichero y después los visualiza. En caso de que queramos añadir bytes al final del
fichero usaremos FileOutputStream con el segundo parámetro del constructor en true.
EscribirFichBytes
package streamsBinarios;
import java.io.*;
public class EscribirFichBytes {
public static void main(String[] args) {
File fichero = new File("."+ File.separator + "src" +
File.separator + "streamsBinarios" + File.separator +
"fichBytes.dat");//declara fichero
//crea flujo de salida hacia el fichero
int i;
try(FileOutputStream fileout = new
FileOutputStream(fichero,true)){
for (i=1; i<100; i++)
fileout.write(i); //escribe datos en el
flujo de salida
} catch (IOException e) {
e.printStackTrace();
}
//crea flujo de entrada
try (FileInputStream filein = new
FileInputStream(fichero)){
//visualiza los datos del fichero
while ((i = filein.read()) != -1) //lee datos del
flujo de entrada
System.out.println(i);
} catch (IOException e) {
e.printStackTrace();
}
}
}
En los siguientes ejemplos se puede ver cómo se escribe y se lee un archivo binario
con DataOutputStream y DataInputStream
EscribirFichData
package streamsBinarios;
import java.io.*;
public class EscribirFichData {
public static void main(String[] args) throws IOException {
File fichero = new File("."+ File.separator + "src" +
File.separator + "streamsBinarios" + File.separator + "fichData.dat");
DataOutputStream dataOS = new DataOutputStream(new
FileOutputStream(fichero));
package streamsBinarios;
import java.io.*;
public class LeerFichData {
public static void main(String[] args) throws IOException {
File fichero = new File("."+ File.separator + "src" +
File.separator + "streamsBinarios" + File.separator + "fichData.dat");
DataInputStream dataIS = new DataInputStream(new
FileInputStream(fichero));
// InputStream fichero = new FileInputStream(""."+ File.separator
+ "src" + File.separator + "streamsBinarios" + File.separator +
"fichData.dat");
// DataInputStream dataIS = new DataInputStream(fichero);
String n;
int e;
try {
while (true) {
n = dataIS.readUTF(); //recupera el nombre
e = dataIS.readInt(); //recupera la edad
System.out.println("Nombre: " + n + ", edad: " + e);
}
}catch (EOFException eo) {}
Los métodos read() o write() pueden lanzar la excepción IOException por lo que es necesario
añadir un throws IOException en el main o bien utilizar el manejador try-catch/try with
resources.
Autoevaluación
Señala si la afirmación es verdadera o falsa:
Persona
package objetosBinarios;
import java.io.Serializable;
EscribirFichObject
package objetosBinarios;
import java.io.*;
Persona persona;
Para leer objetos Persona del fichero necesitamos el flujo de entrada a disco FilelnputStream y
a continuación crear el flujo de entrada ObjectlnputStream que es el que procesa los datos y se
ha de vincular al fichero de FilelnputStream:
LeerFichObject
package objetosBinarios;
import java.io.*;
int i = 1;
try {
while (true) { // lectura del fichero
persona = (Persona) dataIS.readObject();
// leer una Persona
System.out.print(i + "=>");
i++;
System.out.printf("Nombre: %s,
edad: %d %n", persona.getNombre(),persona.getEdad());
}
} catch (EOFException eo) {
System.out.println("FIN DE LECTURA.");
}
dataIS.close(); // cerrar stream de entrada
}
}
La cabecera se crea cada vez que se pone new ObjectOutStream (fichero). Para que no se
añadan estas cabeceras se puede redifinir la clase ObjectOutputStream creando una nueva
clase que la herede (extends). Y dentro de esa clase de redefine el
método writeStreamHeader(), que es el que escribe las cabeceras, para que no haga nada. Así,
si el fichero ya se ha creado se llamará a ese método de la clase redefinida.
/** Redefinición del método de escribir la cabecera para que no haga nada. */
protected void writeStreamHeader() throws IOException
{
}
}
Y dentro de nuestro programa, a la hora de abrir el fichero para añadir nuevos objetos se
pregunta si ya existe. Si existe, se crea el objeto con la clase redefinida y utilizando el constructor
adecuado con parámetro append a true, y si no existe, el fichero se crea con la
clase ObjectOutputStream.
Para los flujos de caracteres, Java dispone de dos clases abstractas: Reader y Writer.
En un programa Java para crear o abrir un fichero se invoca a la clase File y a continuación, se
crea el flujo de entrada hacia el fichero con la clase FileReader. Después se realizan las
operaciones de lectura o escritura y cuando terminemos de usarlo lo cerraremos mediante el
método close(). El siguiente ejemplo lee cada uno de los caracteres del fichero de texto de
nombre LeerFichTexto.java y los muestra en pantalla, los métodos read() pueden lanzar la
excepción IOException, por ello en main() se ha añadido throws IOException ya que no se
incluye el manejador try-catch/try-with-resources:
LeerFichTexto
package streamsTexto;
import java.io.*;
int i;
while ((i = fic.read()) != -1) //se va leyendo un carácter hasta que
lea -1
System.out.print((char) i); //cast a char
}
}
En el ejemplo anterior, la expresión ((char) i) convierte el valor entero recuperado por el método
read() a carácter, es decir, hacemos un cast a char. Se llega al final del fichero cuando el método
read() devuelve -1. Para ir leyendo de 20 en 20 caracteres al método read le pasaremos un array
de carácteres como parámetro.
EscribirFichTexto
package streamsTexto;
import java.io.*;
fic.write("\n");
fic.write(cad);//escribe un array de caracteres
String c="\n*esto es lo ultimo*";
fic.write(c);//escribe un String
}
}
Como se puede observar en el ejemplo, en vez de escribir los caracteres uno a uno, también
podemos escribir todo el array pasando como parámetro e incluso un String.
Debes conocer
Para conocer los métodos que proporciona FileWriter para escritura puedes consultar
directamente la especificación del API de Java 8
Al leer, la clase leerá más datos de los que se hayan pedido. En las siguientes lecturas nos dará
lo que tiene almacenado, hasta que necesite leer otra vez físicamente. Esta forma de trabajar
hace los accesos a disco más eficientes y el programa se ejecuta más rápido.
FileReader no contiene métodos que nos permitan leer líneas completas, pero BufferedReader
sí; dispone del método readLine() que lee una línea del fichero y la devuelve, o devuelve null si
no hay nada que leer o llegamos al final del fichero. También dispone del método read() para
leer un carácter. Para construir un BufferedReader necesitamos la clase FileReader:
El siguiente ejemplo lee el fichero LeerFichTexto.java línea por línea y las va visualizando en
pantalla, en este caso las instrucciones se han agrupado dentro de un bloque try-catch:
LeerFichTextoBuf
package streamsTexto;
import java.io.*;
public class LeerFichTextoBuf {
public static void main(String[] args) {
try{
File fic = new File("."+ File.separator + "src" +
File.separator + "streamsTexto" + File.separator +
"fichtexto.txt");//declara fichero
BufferedReader fichero = new BufferedReader(new FileReader(fic));
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 ");}
}
}
La clase BufferedWriter también deriva de la clase Writer. Esta clase añade un buffer para
realizar una escritura eficiente de caracteres. Para construir un BufferedWriter necesitamos la
clase FileWriter:
EscribirFichTextoBuf
package streamsTexto;
import java.io.*;
public class EscribirFichTextoBuf {
public static void main(String[] args) {
try{
BufferedWriter fichero = new BufferedWriter (new FileWriter("."+
File.separator + "src" + File.separator + "streamsTexto" + File.separator
+ "fichtexto1.txt"));
for (int i=1; i<11; i++){
fichero.write("Fila numero: "+i); //escribe una línea
fichero.newLine(); //escribe un salto de línea
}
fichero.close();
}
catch (FileNotFoundException fn ){
System.out.println("No se encuentra el fichero");}
catch (IOException io) {
System.out.println("Error de E/S ");}
}
}
Por último, la clase PrintWriter, que también deriva de Writer, posee los métodos print(String)
y println(String) (idénticos a los de System.out) para escribir en un fichero. Ambos reciben un
String y lo imprimen en un fichero, el segundo método salta de línea. Para construir un
PrintWriter necesitamos la clase FileWriter:
EscribirFichTextoPrint
package streamsTexto;
import java.io.*;
public class EscribirFichTextoPrint {
public static void main(String[] args) {
try(PrintWriter fichero = new PrintWriter (new
FileWriter("."+ File.separator + "src" + File.separator + "streamsTexto"
+ File.separator + "fichtexto2.txt"))){
for (int i=1; i<11; i++)
fichero.println("Fila numero: "+i); //escribe
una línea
}
catch (FileNotFoundException fn ){
System.out.println("No se encuentra el
fichero");}
catch (IOException io) {
System.out.println("Error de E/S ");}
}
}
Autoevaluación
Mediante las clases que proporcionan buffers se pretende que se hagan lecturas y
escrituras físicas a disco, lo antes posible y cuantas más mejor.
Verdadero Falso
Caso práctico
El momento de programar ha llegado, y Antonio se pregunta qué opción será mejor para el
acceso a los ficheros: si acceso secuencial o aleatorio. ¿Qué uso se le va a dar a estos ficheros?,
¿para qué van a servir cuando la aplicación informática esté en funcionamiento? Esa es la
cuestión clave, piensa Antonio.
Hemos visto que en Java puedes utilizar dos tipos de ficheros (de texto o binarios) y dos tipos
de acceso a los ficheros (secuencial o aleatorio). Si bien, y según la literatura que
consultemos, a veces se distingue una tercera forma de acceso denominada concatenación,
tuberías o pipes.
• Acceso aleatorio: los archivos de acceso aleatorio, al igual que lo que sucede
usualmente con la memoria (RAM=Random Access Memory), permiten acceder a los
datos en forma no secuencial, desordenada. Esto implica que el archivo debe estar
disponible en su totalidad al momento de ser accedido, algo que no siempre es posible.
• Acceso secuencial: En este caso los datos se leen de manera secuencial, desde el
comienzo del archivo hasta el final (el cual muchas veces no se conoce a priori). Este es
el caso de la lectura del teclado o la escritura en una consola de texto, no se sabe cuándo
el operador terminará de escribir.
Víctor Hugo.
Como operaciones más comunes en ficheros de acceso secuencial, tenemos el acceso para:
A menudo, no necesitas leer un fichero de principio a fin, sino simplemente acceder al fichero
como si fuera una base de datos, donde se salta de un registro a otro; cada uno en diferentes
partes del fichero. Java proporciona una clase RandomAccessFile para este tipo de
entrada/salida.
Esta clase:
• Permite leer y escribir sobre el fichero, no son necesarias dos clases diferentes.
• Necesita que le especifiquemos el modo de acceso al construir un objeto de esta clase:
sólo lectura o bien lectura y escritura.
• Posee métodos específicos de desplazamiento como seek(long
posicion) o skipBytes(int desplazamiento) para poder movernos de un registro a
otro del fichero, o posicionarnos directamente en una posición concreta del fichero.
Por esas características que presenta la clase, un archivo de acceso directo tiene sus registros
de un tamaño fijo o predeterminado de antemano.
En el primer caso se pasa un objeto File como primer parámetro, mientras que en el segundo
caso es un String. El modo es: "r" si se abre en modo lectura o "rw" si se abre en modo lectura
y escritura.
Tamaño de otros tipos: short (2 bytes), byte (1 byte), long (8 bytes), boolean (1bit), float (4 bytes),
etc.
El fichero se abre en modo "rw" para lectura y escritura:
EscribirFichAleatorio
package accesoAleatorio;
import java.io.*;
public class EscribirFichAleatorio {
public static void main(String[] args) throws IOException {
File fichero = new File("."+ File.separator + "src" + File.separator +
"accesoAleatorio" + File.separator + "AleatorioEmple.dat");
//declara el fichero de acceso aleatorio
RandomAccessFile file = new RandomAccessFile(fichero, "rw");
//arrays con los datos
String apellido[] = {"FERNANDEZ","GIL","LOPEZ","RAMOS",
"SEVILLA","CASILLA", "REY"};//apellidos
int dep[] = {10, 20, 10, 10, 30, 30, 20}; //departamentos
Double salario[]={1000.45, 2400.60, 3000.0, 1500.56,
2200.0, 1435.87, 2000.0};//salarios
El siguiente ejemplo toma el fichero anterior y visualiza todos los registros. El posicionamiento
para empezar a recorrer los registros empieza en 0, para recuperar los siguientes registros hay
que sumar 36 (tamaño del registro) a la variable utilizada para el posicionamiento:
LeerFichAleatorio
package accesoAleatorio;
import java.io.*;
public class LeerFichAleatorio {
public static void main(String[] args) throws IOException {
File fichero = new File ("."+ File.separator + "src" + File.separator
+ "accesoAleatorio" + File.separator + "AleatorioEmple.dat");
//declara el fichero de acceso aleatorio
RandomAccessFile file = new RandomAccessFile(fichero, "r");
//
int id, dep, posicion;
Double salario;
char apellido[] = new char[10], aux;
if(id >0)
System.out.printf("ID: %s, Apellido: %s, Departamento: %d,
Salario: %.2f %n",
id, apellidos.trim(), dep, salario);
Para consultar un empleado determinado no es necesario recorrer todos los registros del
fichero, conociendo su identificador podemos acceder a la posición que ocupa dentro del
mismo y obtener sus datos
Autoevaluación
Indica si la afirmación es verdadera o falsa:
Verdadero Falso
Anexo I.- Código de crear un fichero.
try {
// Creamos el objeto que encapsula el fichero
File fichero = new File("c:\\prueba\\miFichero.txt");
// A partir del objeto File creamos el fichero físicamente
if (fichero.createNewFile())
System.out.println("El fichero se ha creado correctamente");
else
System.out.println("No ha podido ser creado el fichero");
} catch (Exception ioe) {
ioe.getMessage();
}
// Crear un directorio
boolean exito = (new File(directorio)).mkdir();
if (exito)
System.out.println("Directorio: " + directorio + " creado");
// Crear varios directorios
exito = (new File(varios)).mkdirs();
if (exito)
System.out.println("Directorios: " + varios + " creados");
}catch (Exception e){
System.err.println("Error: " + e.getMessage());
}