En esta secci�n vamos a empezar a trabajar con flujos "reales", creados por nosotros mismos. El primero tipo de flujo va a ser FileInputStream. Esta clase, heredera directa de InputStream, es una clase no abstracta, destinada a la lectura de archivos en disco. Posteriormente veremos la clase complementaria, FileOutputStream.
�Utilizaci�n de la clase FileInputStream
Para crear un objeto de tipo FileInputStream, necesitamos indicarle al constructor de la clase el nombre del archivo que queremos leer. Esto crear� un objeto que, a todos los efectos, se comportar� como un objeto de tipo InputStream, es decir, podremos considerarlo como un "tubo" del cual extraemos bytes de uno en uno. No nos importa el hecho de que en el otro extremo del "tubo" haya un archivo del que vienen los datos. Podremos trabajar con el "tubo" usando las t�cnicas vistas en el caso de InputStream.
La forma m�s directa de abrir un archivo para leer su contenido es la siguiente. En este ejemplo, abrimos el archivo c:\dir\subdir\archivo y realizamos la suma de sus bytes.
try { FileInputStream fis = new FileInputStream("c:\\dir\\subdir\\archivo"); int parcial,total=0; while ((parcial=fis.read())!=-1) total += parcial; } catch(FileNotFoundException fnfe) { /* Archivo no encontrado */ } catch (IOException ioe) { /* Error al leer */ }
En este fragmento de c�digo tenemos que comprobar tambi�n que no se produzca una excepci�n porque el archivo no exista. Si no lo comprob�ramos, el control pasar�a al catch de IOException, que es la clase "madre" de FileNotFoundException. Tambi�n hay que resaltar las dobles barras hacia atr�s, necesarias por la forma que tiene Java de tratar los c�digos de escape en las cadenas de texto.
Es importante ver que, aunque el objeto fis sea de tipo FileInputStream, podemos trabajar con �l como si fuera un objeto de tipo InputStream, debido a la herencia. Esto es com�n a casi todos los flujos.
�La clase File
En la secci�n anterior hemos visto uno de los posibles constructores de la clase FileInputStream: el que recibe como par�metro un nombre de archivo para leer. Existe otras dos variantes: una que recibe un objeto de tipo File y otra que recibe un objeto de tipo FileDescriptor. Veamos en qu� consiste la clase File.
La clase File sirve para encapsular la interacci�n de nuestros programas con el sistema de archivos. Mediante la clase File no nos limitamos a leer el contenido de un archivo, como ocurr�a con la clase FileInputStream, sino que podemos obtener informaci�n adicional, como el tama�o del archivo, su tipo, su fecha de creaci�n, los permisos de acceso que tenemos sobre �l, etc.
Adem�s, la clase File es la �nica forma que tenemos de trabajar con directorios (crearlos, ver los archivos que contienen, cambiar el nombre o borrar los archivos, etc.)
La forma m�s sencilla de crear un objeto File es:
File miArchivo = new File("c:\\temp\\archivo.txt");
Es muy importante darse cuenta de la diferencia entre un objeto de tipo File y el archivo o directorio al que se refiere. Por ejemplo, el archivo c:\temp\archivo.txt que aparece en el fragmento de c�digo anterior no tiene por qu� existir. Para saber si un objeto File se refiere a un archivo existente podemos usar el m�todo exists():
File miArchivo = new File("c:\\temp\\archivo.txt"); if (miArchivo.exists()) { /* El archivo existe */ } else { /* El archivo no existe */ }
Podemos obtener m�s informaci�n de un objeto File:
File f = new File("c:\\temp\\archivo.txt"); long = f.length(); /* Tama�o del archivo */ boolean lectura = f.canRead() /* �Podemos leer el archivo? */ boolean escritura = f.canWrite() /* �Podemos escribir el archivo? */ if (f.delete()) { /* Archivo borrado con �xito */ } else { /* El archivo no se ha podido borrar */ } String nombre = f.getName() /* Nombre (sin directorio) del archivo */ String dir = f.getParent() /* Directorio del archivo */ if (f.isDirectory()) { /* Es un directorio */ } else { /* No es un directorio */ } if (f.isFile()) { /* Es un archivo normal */ } else { /* No es un archivo normal */ } long modificado = f.lastModified(); /* Fecha de �ltima modificaci�n */ if (f.renameTo(new File("c:\\temp\\otroArchivo.txt"))) { /* Nombre de archivo modificado */ } else { /* Nombre de archivo no modificado */ }
Las siguientes l�neas de c�digo muestran algunos ejemplo sobre como trabajar con directorios mediante la clase File:
File f = new File("c:\\temp"); String[] lista = f.list(); /* Obtenemos la lista de archivos */ for(int n=0;n<lista.length;n++) /* Los imprimimos */ System.out.println("Archivo n� " + n + " : " + lista[n]); File g = new File("c:\\temp\\dir1"); if (g.mkdir()) { /* Hemos creado el directorio dir1 en el directorio c:\temp, previamente existente. */ } else { /* No lo hemos podido crear */ } File h = new File("c:\\temp\\dirA\\dirB\\dirC\\dirD"); if (h.mkdirs()) { /* Hemos creado el directorio dirD, junto con los directorio intermedios necesarios. */ } else { /* No lo hemos podido crear */ }
�Utilizaci�n de la clase FileOutputStream
El pr�ximo paso es el esperado: abrir un archivo y escribir en �l. Hay varias formas de realizar esto, todas pr�cticamente sim�tricas a las utilizadas para leer archivos. Por ejemplo:
/* Creamos un stream de salida sobre el archivo */ FileOutputStream fos = new FileOutputStream("c:\\temp\\archivo.dat"); /* Vamos a escribir los n�meros del 1 al 10 en el archivo */ for(int n=0;n<10;n++) { fos.write(n); } fos.close();
Otro ejemplo podr�a ser el siguiente programa, que pretende ser una versi�n simplificada del comando copy de MS-DOS:
import java.io.*; class copy { public static void main(String args[]) { String origen = args[0]; String destino = args[1]; byte buffer[]= new byte[1024]; int cuenta; try { FileInputStream fis = new FileInputStream(origen); FileOutputStream fos = new FileOutputStream(destino); while((cuenta=fis.read(buffer))>0) fos.write(buffer,cuenta); } catch(IOException ioe) { System.err.println("Se ha producido un error"); ioe.printStackTrace(); } } }
Si ejecutamos este programa mediante
java copy c:\temp\archivo1.txt "c:\mis documentos\archivo2.txt"
el programa copiar� el contenido de un archivo en el otro. Si el archivo destino ya existe, ser� borrado. Si el archivo origen no existe, el catch del programa nos avisar� y volcar� en pantalla el contenido de la pila de llamadas (aunque en este programa tan simple no sea de ninguna utilidad).
Consultando la documentaci�n del JDK podemos ver que tambi�n podemos crear un objeto FileOutputStrem mediante un objeto File. Su utilizaci�n ser�a similar a la que hemos visto antes para FileInputStream.