Manejo Ficheros
Manejo Ficheros
Manejo Ficheros
1. INTRODUCCIN
Un fichero o archivo es un conjunto de bits almacenado en un dispositivo, como por ejemplo
un disco duro. La ventaja de utilizar ficheros es que los datos que guardamos permanecen en el
dispositivo aun cuando apaguemos el ordenador, es decir, no son voltiles. Los ficheros tienen
un nombre y se ubican en directorios o carpetas, el nombre debe ser nico en ese directorio; es
decir, no puede haber dos ficheros con el mismo nombre en el mismo directorio. Por
convencin cuentan con diferentes extensiones que por lo general suelen ser de 3 letras (PDF,
DOC, GIF,...) y nos permiten saber el tipo de archivo.
Un fichero est formado por un conjunto de registros o lneas y cada registro por un conjunto de
campos relacionados, por ejemplo un fichero de empleados puede contener datos de los
empleados de una empresa, un fichero de texto puede contener lneas de texto, correspondientes
a lneas impresas en una hoja de papel. La manera en que se agrupan los datos en el fichero
depende completamente de la persona que lo disee.
2. CLASES ASOCIADAS A LAS OPERACIONES DE GESTIN DE
FICHEROS
Antes de ver las clases que leen y escriben datos en ficheros, vamos a manejar la clase File. Esta
clase proporciona un conjunto de utilidades relacionadas con los ficheros que nos van a
proporcionar informacin acerca de los mismos, su nombre, sus atributos, los directorios, etc.
Puede representar el nombre de un fichero particular o los nombres de un conjunto de ficheros
de un directorio, tambin se puede usar para crear un nuevo directorio o una trayectoria de
directorios completa si esta no existe. Para crear un objeto File, se puede utilizar cualquiera de
los tres constructores siguientes:
File(String directorioyfichero): en Linux: new File("/directorio/fichero.txt"); en
plataformas Microsoft Windows: new File("C:\\directorio\\fichero.txt");
File(String directorio, String nombrefichero): new File("directorio", "fichero.txt");
File(File directorio, String fichero): new File(new File("directorio"), "fichero.txt")
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.
Algunos mtodos importantes del objeto File son:
getName(): devuelve el nombre del fichero o directorio.
getPath(): devuelve el camino relativo.
getAbsolutePath(): devuelve el camino absoluto del fichero/directorio.
canRead(): devuelve true si el fichero se puede leer.
canWrite(): devuelve true si el fichero se puede escribir.
length(): nos devuelve el tamao del fichero en bytes.
createNewFile(): crea un nuevo fichero, vaco, asociado a File si y solo si no existe un
fichero con dicho nombre.
delete(): borra el fichero o directorio asociado al File.
Exists(): devuelve true si el fichero/directorio existe.
getParent(): devuelve el nombre del directorio padre, o nuil si no existe.
isDirectory(): devuelve true si el objeto File corresponde a un directorio.
isFile(): devuelve true si el objeto File corresponde a un fichero normal.
Mkdir(): crea un directorio con el nombre indicado en la creacin del objeto File.
renameTo(File nuevonombre): renombra el fichero.
Ejemplos:
Ver ficheros existentes en el directorio actual. (VerDir.java)
Crea un directorio (de nombre NUEVODIR) en el directorio actual, a continuacin crea dos
ficheros vacos en dicho directorio y uno de ellos lo renombra. (CrearDir.java)
Informacin de un fichero (VerInf.java)
3. FLUJOS O STREAMS.TIPOS
El sistema de entrada/salida en Java presenta una gran cantidad de clases que se implementan en el
paquete java.io. Usa la abstraccin del flujo (stream) para tratar la comunicacin de informacin
entre una fuente y un destino; dicha informacin puede estar en un fichero en el disco duro, en la
memoria, en algn lugar de la red, e incluso, en otro programa. Cualquier programa que tenga que
obtener informacin de cualquier fuente necesita abrir un stream, igualmente si necesita enviar
informacin abrir un stream y se escribir la informacin en serie. La vinculacin de este stream al
dispositivo fsico la hace el sistema de entrada y salida de Java. Se definen dos tipos de flujos:
Flujos de bytes (8 bits): realizan operaciones de entradas y salidas de bytes y su uso
est orientado a la lectura/escritura de datos binarios. Todas las clases de flujos de bytes
descienden de las clases InputStream y OutputStream, cada una de estas clases tienen
varias subclases que controlan las diferencias ente los distintos dispositivos de
entrada/salida que se pueden utilizar.
Flujos de caracteres (16 bits): realizan operaciones de entradas y salidas de caracteres.
El flujo de caracteres viene gobernado por las clases Reader y Writer. La razn de ser
de estas clases es la internacionalizacin; la antigua jerarqua de flujos de E/S solo
soporta flujos de 8 bits, no manejando caracteres Unicode de 16 bits que se utilizaba
con fines de internacionalizacin.
FLUJOS DE BYTES (BYTE STREAMS)
La clase InputStream representa las clases que producen entradas de distintas fuentes, estas fuentes pueden
ser: un array de bytes, un objeto String, un fichero, una "tubera" (se ponen los elementos en un extremo y salen
por el otro), una secuencia de otros flujos, otras fuentes como una conexin a Internet, etc.
Los tipos de OutputStream incluyen las clases que deciden donde ir la salida: a un array de bytes, un fichero
o una "tubera".
FLUJOS DE CARACTERES (CHARACTER STREAMS)
Las clases Reader y Writer manejan flujos de caracteres Unicode. Hay ocasiones en las que hay
que usar las clases que manejan bytes en combinacin con las clases que manejan caracteres. Para
lograr esto hay clases "puente" (es decir, convierte los streams de bytes a streams de caracteres):
InputStreamReader que convierte un InputStream en un Reader (lee bytes y los convierte en
caracteres) y OutputStreamReader que convierte un OutputStream en un Writer.
La siguiente tabla muestra la correspondencia entre las clases de flujos de bytes y de caracteres:
4. FORMAS DE ACCESO A UN FICHERO
Hay dos formas de acceso a la informacin almacenada en un fichero: acceso secuencial y
acceso directo o aleatorio:
Acceso secuencial: los datos o registros se leen y se escriben en orden, del mismo
modo que se hace en una antigua cinta de vdeo. Si se quiere acceder a un dato o un
registro que est hacia la mitad del fichero es necesario leer antes todos los anteriores.
La escritura de datos se har a partir del ltimo dato escrito, no es posible hacer
inserciones entre los datos que ya hay escritos.
Acceso directo o aleatorio: permite acceder directamente a un dato o registro sin
necesidad de leer los anteriores y se puede acceder a la informacin en cualquier orden.
Los datos estn almacenados en registros de tamao conocido, nos podemos mover de
un registro a otro de forma aleatoria para leerlos o modificarlos.
En Java el acceso secuencial ms comn en ficheros puede ser binario o a caracteres. Para el
acceso binario: se usan las clases FilelnputStream y FileOutputStream; para el acceso a
caracteres (texto) se usan las clases FileReader y FileWriter. En el acceso aleatorio se utiliza la
clase RandomAccessFile
5. OPERACIONES SOBRE FICHEROS
Las operaciones bsicas que se realizan sobre cualquier fichero independientemente de la forma
de acceso al mismo son las siguientes:
Creacin del fichero. Ei fichero se crea en el disco con un nombre que despus se debe
utilizar para acceder a l. La creacin es un proceso que se realiza una vez.
Apertura del fichero. Para que un programa pueda operar con un fichero, la primera
operacin que tiene que realizar es la apertura del mismo. El programa utilizar algn
mtodo para identificar el fichero con el' que quiere trabajar, por ejemplo asignar a una
variable el descriptor del fichero.
Cierre del fichero. El fichero se debe cerrar cuando el programa no lo vaya a utilizar.
Normalmente suele ser la ltima instruccin del programa.
Lectura de los datos del fichero. Este proceso consiste en transferir informacin del
fichero a la memoria principal, normalmente a travs de alguna variable o variables de
nuestro programa, en las que se depositarn los datos extrados del fichero.
Escritura de datos en el fichero. En este caso el proceso consiste en transferir informacin
de la memoria (por medio de las variables del programa) al fichero.
Normalmente las operaciones tpicas que se realizan sobre un fichero una vez abierto son las
siguientes:
Altas: consiste en aadir un nuevo registro al fichero.
Bajas: consiste en eliminar del fichero un registro ya existente. La eliminacin puede ser
lgica, cambiando el valor de algn campo del registro que usemos para controlar dicha
situacin; o fsica, eliminando fsicamente el registro del fichero. El borrado fsico consiste
muchas veces en reescribir de nuevo el fichero en otro fichero sin los datos que se desean
eliminar y luego renombrarlo al fichero original.
Modificaciones: consiste en cambiar parte del contenido de un registro. Antes de realizar la
modificacin ser necesario localizar el registro a modificar dentro del fichero; y una vez
localizado se realizan los cambios y se reescribe el registro.
Consultas: consiste en buscar en el fichero un registro determinado.
6. CLASES PARA GESTIN DE FLUJOS DE DATOS DESDE/HACIA
FICHEROS
FICHEROS DE TEXTO
Los ficheros de texto, los que normalmente se generan con un editor, almacenan caracteres
alfanumricos en un formato estndar (ASCII, UNICODE, UTF8, etc.). Para trabajar con ellos
usaremos las clases FileReader para leer caracteres y FileWriter para escribir los caracteres en el
fichero.
Cuando trabajamos con ficheros, cada vez que leemos o escribimos en uno, debemos hacerlo dentro
de un manejador de excepciones try-catch. Al usar la clase FileReader se puede generar la
excepcin FileNotFoundException (porque el nombre del fichero no exista o no sea vlido) y al usar
la clase FileWriter la excepcin IOException (el disco est lleno o protegido contra escritura).
Los mtodos que proporciona la clase FileReader para lectura son los siguientes, estos mtodos
devuelven el nmero de caracteres ledos 0 -1 si se ha llegado al final del fichero:
int read(): lee un carcter y lo devuelve.
int read(char[] buf): lee hasta buf.length caracteres de datos de una matriz de
caracteres (buf). Los caracteres ledos del fichero se van almacenando en buf.
int read(char[] buf, int desplazamiento, int n): lee hasta n caracteres de datos de la
matriz buf comenzando por buffdesplazamiento] y devuelve el nmero ledo de
caracteres.
Los mtodos que proporciona la clase FileWriter para escritura son:
void write(int c): escribe un carcter.
void write(char[] buf): escribe un array de caracteres.
void write(char[] buf, int desplazamiento , int n): escribe n caracteres de datos en la
matriz buf y comenzando por buf [desplazamiento].
void write(String str): escribe una cadena de caracteres.
append(char c): aade un carcter a un fichero.
Ejemplos
Leer un fichero de texto y buf (LeerFichTexto.java y LeerFichTextoBuf.java)
Escribir un fichero de texto y buf (EscribirFichTexto.java y EscribirFichTextoBuf.java)
FICHEROS BINARIOS
Los ficheros binarios almacenan secuencias de dgitos binarios que no son legibles directamente por
el usuario como ocurra con los ficheros de texto. Tienen la ventaja de que ocupan menos espacio en
disco. En Java, las dos clases que nos permiten trabajar con ficheros son FilelnputStream (para
entrada) y FileOutputStream (para salida), estas trabajan con flujos de bytes y crean un enlace entre
el flujo de bytes y el fichero.
Los mtodos que proporciona la clase FilelnputStream para lectura son similares a los vistos para la
clase FileReader, estos mtodos devuelven el nmero de bytes ledos 0 - 1 si se ha llegado al final
del fichero:
int read(): lee un byte y lo devuelve.
int read(byte[] b): lee hasta b.length bytes de datos de una matriz de bytes.
int read(byte[] b, int desplazamiento , int n): lee hasta n bytes de la matriz b
comenzando por b[ desplazamiento] y devuelve el nmero ledo de bytes.
Los mtodos que proporciona la clase FileOutputStream para escritura son:
void write(int b): escribe un byte.
void write(byte[] b): escribe b.length bytes.
void write(byte[] b, int desplazamiento , int n): escribe n bytes a partir de la matriz
de bytes de entrada y comenzando por b [desplazamiento].
Para leer y escribir datos de tipos primitivos: int, float, long, etc. usaremos las clases
DatalnputStream y DataOutputStream. Estas clases adems de los mtodos read() y write()
vistos anteriormente proporcionan mtodos para la lectura y escritura de tipos primitivos de un
modo independiente de la mquina. Algunos de los mtodos se muestran en la siguiente tabla:
Ejemplos
Escribir bytes en un fichero y visualizarlo (EscribirFichBytes.java)
Insertar datos en el fichero FichData.dat (EscribirFichData.java)
Visualizar los datos grabados anteriormente en el fichero (LeerFichData.java)
OBJETOS SERIALIZABLES
Hemos visto cmo se guardan los tipos de datos primitivos en un fichero, pero por ejemplo, si
tenemos un objeto de tipo empleado con varios atributos (el nombre, la direccin, el salario, el
departamento, el oficio, etc.) y queremos guardarlo en un fichero, tendramos que guardar cada
atributo que forma parte del objeto por separado, esto se vuelve engorroso si tenemos gran cantidad
de objetos.
Por ello Java nos permite guardar objetos en ficheros binarios; para poder hacerlo, el objeto tiene
que implementar la interfaz Serializable que dispone de una serie de mtodos con los que podremos
guardar y leer objetos en ficheros binarios. Los ms importantes a utilizar son:
void readObject(java.io.ObjectInputStream stream) throws IOException,
ClassNotFouna Exception: para leer un objeto.
void writeObject(ObjectOutputStream stream) throws IOException: para
escribir un objeto.
La serializacin de objetos de Java permite tomar cualquier objeto que implemente la interfaz
Serializable y convertirlo en una secuencia de bits, que puede ser posteriormente restaurada para
regenerar el objeto original.
Ejemplos
Visualiza los datos grabados anteriormente en el fichero, se deben recuperar en el
mismo orden en el que se insertaron (Persona.java, EscribirFichObject.java y
LeerFichObject.java)
FICHEROS DE ACCESO ALEATORIO
Hasta ahora todas las operaciones que hemos realizado sobre los ficheros se realizaban de forma
secuencial. Se empezaba la lectura en el primer byte o el primer carcter o el primer objeto y
seguidamente, se lean los siguientes uno a continuacin de otro hasta llegar al fin del fichero.
Igualmente cuando escribamos los datos en el fichero se iban escribiendo a continuacin de la
ltima informacin escrita. Java dispone de la clase RandomAccessFile que dispone de mtodos
para acceder al contenido de un fichero binario de forma aleatoria (no secuencial) y para
posicionarnos en una posicin concreta del mismo. Esta clase no es parte de la jerarqua
InputStream/OutputStream, ya que su comportamiento es totalmente distinto puesto que se puede
avanzar y retroceder dentro de un fichero.
Disponemos de dos posibilidades para crear el fichero de acceso aleatorio:
Escribiendo el nombre del fichero: fichero = new RandomAccessFile(String
nombre,Strig modo Acceso );
Con un objeto file: fichero = new RandomAccessFile( Filefich, String modoAcceso
);
El argumento modoAcceso puede ser: "r" para solo lectura o "rw" para lectura y escritura. Una vez
abierto el fichero pueden usarse los mtodos read() y write() de las clases DatalnputStream y
DataOutputStream (vistos anteriormente). La clase RandomAccessFile maneja un puntero que
indica la posicin actual en el fichero. Cuando en el fichero se crea el puntero se coloca en (),
apuntando al principio del mismo. Las sucesivas llamadas a los mtodos read() y write() ajustan
el puntero segn la cantidad de bytes ledos o escritos.
Los mtodos ms importantes son:
long getFilePointer(): devuelve la posicin actual del puntero del fichero.
void seek(long posicin): coloca el puntero del fichero en una posicin
determinada desde el comienzo del mismo.
long length(): devuelve el tamao del fichero en bytes. La posicin length()
marca el final del fichero.
int skipBytes(int desplazamiento): desplaza el puntero desde la posicin actual
el nmero de bytes indicados en desplazamiento.
Ejemplos
Crear un fichero aleatorio (EscribirFichAleatorio.java)
Leer un fichero aleatorio (LeerFichAleatorio.java)
7. FICHEROS XML
XML (eXtensible Markup Language- Lenguaje de Etiquetado Extensible) es un metalenguaje, es
decir, un lenguaje para la definicin de lenguajes de marcado. Nos permite jerarquizar y estructurar
la informacin as como describir los contenidos dentro del propio documento. Los ficheros XML
son ficheros de texto escritos en lenguaje XML donde la informacin est organizada de forma
secuencial y en orden jerrquico. Existen una serie de marcas especiales como son los smbolos
menor que, < y mayor que, > que se usan para delimitar las marcas que dan la estructura al
documento. Cada marca tiene un nombre y puede tener atributos.
Para leer los ficheros XML y acceder a su contenido y estructura, se utiliza un procesador de
XML o parser. El procesador lee los documentos y proporciona acceso a su contenido y estructura.
Algunos de los procesadores ms empleados son: DOM: Modelo de Objetos de Documento y SAX:
API Simple para XML. Son independientes del lenguaje de programacin y existen versiones
particulares para Java, VisualBasic, C, etc. Utilizan dos enfoques muy diferentes:
DOM: un procesador XML que utilice este planteamiento almacena toda la
estructura del documento en memoria en forma de rbol con nodos padre,
nodos hijo y nodos finales (que son aquellos que no tienen descendientes). Una vez
creado el rbol, se van recorriendo los diferentes nodos y se analiza a qu tipo
particular pertenecen. Tiene su origen en el W3C. Este tipo de procesamiento
necesita ms recursos de memoria y tiempo sobre todo si los ficheros XML a
procesar son bastante grandes y complejos.
SAX: un procesador que utilice este planteamiento lee un fichero XML de forma
secuencial y produce una secuencia de eventos (comienzo/fin del documento,
comienzo/fin de una etiqueta, etctera) en funcin de los resultados de la lectura.
Cada evento invoca a un mtodo definido por el programador. Este tipo de
procesamiento prcticamente no consume memoria, pero por otra parte, impide
tener una visin global del documento por el que navegar.
ACCESO A FICHEROS XML CON DOM
Para poder trabajar con DOM en Java necesitamos las clases e interfaces que componen el paquete
org.w3c.dom(contenido en el JSDK) y el paquete javax.xml.parsers del API estndar de Java que
proporciona un par de clases abstractas que toda implementacin DOM para Java debe extender.
Estas clases ofrecen mtodos para cargar documentos desde una fuente de datos (fichero,
InputStream, etc.). Contiene dos clases fundamentales: DocumentBuilderFactory y
DocumentBuilder.
DOM no define ningn mecanismo para generar un fichero XML a partir de un rbol DOM. Para eso
usaremos el paquete javax.xml.transformque permite especificar una fuente y un resultado. La
fuente y el resultado pueden ser ficheros, flujos de datos o nodos DOM entre otros.
Los programas Java que utilicen DOM necesitan estas interfaces (no se exponen todas, solo
algunas de las que usaremos en los ejemplos):
Document. Es un objeto que equivale a un ejemplar de un documento XML.
Permite crear nuevos nodos en el documento.
Element. Cada elemento del documento XML tiene un equivalente en un
objeto de este tipo. Expone propiedades y mtodos para manipular los
elementos del documento y sus atributos.
Node. Representa a cualquier nodo del documento.
NodeList. Contiene una lista con los nodos hijos de un nodo.
Attr. Permite acceder a los atributos de un nodo.
Text. Son los datos carcter de un elemento.
CharacterData. Representa a los datos carcter presentes en el documento.
Proporciona atributos y mtodos para manipular los datos de caracteres.
DocumentType. Proporciona informacin contenida en la etiqueta
<!DOCTYPE>.
Ejemplos
Crear ficheros XML (CrearEmpleadoXMLDOM.java)
Leer un fichero XML (LecturaEmpleadoXMLDOM.java)
ACCESO A FICHEROS XML CON SAX
Es un conjunto de clases e interfaces que ofrecen una herramienta muy til para el procesamiento de
documentos XML. Permite analizar los documentos de forma secuencial (es decir, no carga todo
el fichero en memoria como hace DOM), esto implica poco consumo de memoria aunque los
documentos de gran tamao en contraposicin, impide tener una visin global del documento que se
va a analizar. SAX es ms complejo de programar que DOM, es un API totalmente escrita en Java e
incluida dentro del JRE (Java Runtime Environment o conjunto de utilidades que permite la
ejecucin de programas) que nos permite crear nuestro propio parser de XML.
La lectura de un documento XML produce eventos que ocasiona la llamada a mtodos, los eventos
son encontrar la etiqueta de inicio y fin del documento (startDocument() y endDocument(), la
etiqueta de inicio y fin de un elemento (startElement() y endElement()), los caracteres entre
etiquetas (characters()), etc.:
Ejemplo
SAX (SAX.java)
Conversin de ficheros a formato XSLT (Convertidor.java)
8. EXCEPCIONES: DETECCIN Y TRATAMIENTO
Una excepcin es un evento que ocurre durante la ejecucin del programa que interrumpe el
flujo normal de las sentencias. Cuando no es capturada por el programa, se captura por el gestor
de excepciones por defecto que retorna un mensaje y detiene el programa.
Ejemplo
Excepcin y visualizacin del mensaje de error (EjemploExcepcion.java)
Excepciones y captura de tres tipos (EjemploExcepciones.java)