% Activate the following line by filling in the right side. If for example the name of the root file is Main.tex, write
% "...root = Main.tex" if the chapter file is in the same directory, and "...root = ../Main.tex" if the chapter is in a subdirectory.
 
%!TEX root =  ../notas_java.tex

\chapter[Java I/O]{Java I/O}

Una forma sencilla de hacer la lectura de archivos es utilizando la clase  File y la clase RandomAccessFile. A continuación se muestran a detalle el uso de estas dos clases.

\section{La clase File}


Antes de proceder al estudio de las clases que describen la entrada/salida vamos a estudiar la clase File, que nos proporciona información acerca de los archivos, de sus atributos, de los directorios, etc. También explicaremos cómo se crea un filtro mediante el interface FilenameFilter para obtener la lista de los archivos que tengan por ejemplo, la extensión .java.

La clase File tiene tres constructores

\begin{verbatim}
    File(String path)
    File(String path, String name)
    File(File dir, String name)
\end{verbatim}

El parámetro path indica el camino hacia el directorio donde se encuentra el archivo, y name indica el nombre del archivo. Los métodos más importantes que describe esta clase son los siguientes:

\begin{verbatim}
    String getName()
    String getPath()
    String getAbsolutePath()
    boolean exists()
    boolean canWrite()
    boolean canRead
    boolean isFile()
    boolean isDirectory()
    boolean isAbsolute()
    long lastModified()
    long length()
    boolean mkdir()
    boolean mkdirs()
    boolean renameTo(File dest);
    boolean delete()
    String[] list()
    String[] list(FilenameFilter filter)
\end{verbatim}

Mediante un ejemplo explicaremos algunos de los métodos de la clase File.

Creamos un objeto fichero de la clase File, pasándole el nombre del archivo, en este caso, el nombre del archivo código fuente ArchivoApp1.java.

\begin{verbatim}
    File fichero=new File("ArchivoApp1.java");
\end{verbatim}

Si este archivo existe, es decir, si la función exists devuelve true, entonces se obtiene información acerca del archivo:

\begin{verbatim}
    getName devuelve el nombre del archivo
    getPath devuelve el camino relativo
    getAbsolutePath devuelve el camino absoluto.
    canRead nos indice si el archivo se puede leer.
    canWrite nos indica si el archivo se puede escribir
    length nos devuelve el tamaño del archivo, si dividimos la cantidad devuelta entre 1024 obtenemos el tamaño del archivo en KB.

    if(fichero.exists()){
        System.out.println("Nombre del archivo "+fichero.getName());
        System.out.println("Camino             "+fichero.getPath());
        System.out.println("Camino absoluto    "+fichero.getAbsolutePath());
        System.out.println("Se puede escribir  "+fichero.canRead());
        System.out.println("Se puede leer      "+fichero.canWrite());
        System.out.println("Tamaño             "+fichero.length());
   }
\end{verbatim}

\begin{verbatim}
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.StringTokenizer;
\end{verbatim}

\section{La clase RandomAccessFile}

 La clase Java RandomAccessFile se utiliza para acceder a un fichero de forma aleatoria.
Los constructores de la clase son:

RandomAccessFile(String path, String modo);
RandomAccessFile(File objetoFile, String modo);

Lanzan una excepción FileNotFoundException.
El argumento modo indica el modo de acceso en el que se abre el fichero.

Los valores permitidos para este parámetro son:
modo ``r" : Abre el fichero en modo solo lectura.El fichero debe existir. Una operación de escritura en este fichero lanzará una excepción IOException.

modo ``rw" : Abre el fichero en modo lectura y escritura. Si el fichero no existe se crea.

Ejemplo: abrir un fichero aleatorio para lectura

Se abre el fichero clientes.dat para lectura usando el primer constructor.

\begin{verbatim}
RandomAccessFile fichero = new RandomAccessFile("/ficheros/clientes.dat", "r");
\end{verbatim}

Ejemplo : abrir un fichero aleatorio para lectura/escritura
Se abre el fichero personas.dat para lectura/escritura usando el segundo constructor. Si el fichero no existe se crea.

\begin{verbatim}
File f = new File ("/ficheros/personas.dat");
RandomAccessFile fichero = new RandomAccessFile(f, "rw");
\end{verbatim}

ACCESO A LOS DATOS EN FICHEROS ALEATORIOS
Para acceder de forma aleatoria a los datos contenidos en el fichero, la clase RandomAccessFile dispone de varios métodos. Entre ellos:

long getFilePointer(); Devuelve la posición actual del puntero del fichero. Indica la posición (en bytes) donde se va a leer o escribir.

long length(); Devuelve la longitud del fichero en bytes.

void seek(long pos); Coloca el puntero del fichero en una posición pos determinada. La posición se da como un desplazamiento en bytes desde el comienzo del fichero. La posición 0 indica el principio del fichero. La posición length() indica el final del fichero.

Además dispone de métodos de lectura/escritura:

public int read(): Devuelve el byte leído en la posición marcada por el puntero. Devuelve -1 si alcanza el final del fichero. Se debe utilizar este método para leer los caracteres de un fichero de texto.

public final String readLine(): Devuelve la cadena de caracteres que se lee, desde la posición marcada por el puntero, hasta el siguiente salto de línea que se encuentre.

public xxx readXxx(): Hay un método read para cada tipo de dato básico: readChar, readInt, readDouble, readBoolean, etc.

public void write(int b) : Escribe en el fichero el byte indicado por parámetro. Se debe utilizar este método para escribir caracteres en un fichero de texto.

public final void writeBytes(String s) : Escribe en el fichero la cadena de caracteres indicada por parámetro.

public final void writeXxx(argumento): También existe un método write para cada tipo de dato básico: writeChar, writeInt, writeDouble, writeBoolean, etc.

\subsection{Ejemplos de operaciones con ficheros de acceso aleatorio}

\begin{verbatim}
public class Archivo {
    static String ruta = "/Users/felix/fie_mac/public_html/programacion_java/codigos/Capitulo_9/";
    static public void ejemplo1(){
        File arch = new File(ruta+"un_archivo.txt");
        
        if(arch.exists()) 
            System.out.println("Si existe el archivo");
            
        
        else
            System.out.println("No existe el arvhivo");
        
    }
    
    static public void ejemplo2() throws FileNotFoundException{
        RandomAccessFile arch = new RandomAccessFile(ruta+"un_archivo.txt", "r");
        String linea;
        int lineas = 0;
        try {
            while((linea = arch.readLine())!=null) {
                System.out.println(linea);
                lineas ++;
            }
            arch.close();
        } catch (IOException ex) {
            System.out.println("No existe el archivo");
        }
        System.out.println("El archivo tiene " + lineas +" lineas");
    }

    static public void ejemplo3() throws FileNotFoundException, IOException{
        RandomAccessFile arch = new RandomAccessFile(ruta+"salida.txt", "rw");
        int i, f1=0, f2 = 1, f3;
        
        for(i=0; i<10; i++) {
            f3 = f2 + f1; 
            System.out.println(f3);
            arch.writeBytes(Integer.toString(f3)+", ");
            f1 = f2;
            f2 = f3;
        }      
        arch.close();
    }

    static public void ejemplo4() throws FileNotFoundException, IOException{
        RandomAccessFile arch = new RandomAccessFile(ruta+"que_es.txt", "rw");
        int i,  N = 100;
        double theta = 2.0*Math.PI/(double) N;
        double x, y;
        
        for(i=0; i<100; i++) {
            x = 10.0*Math.cos(theta*i);
            y = 10.0*Math.sin(theta*i);
            arch.writeBytes(x + ", " + y + "\n");
        }      
        arch.close();
    }
    
    static public void ejemplo5() throws FileNotFoundException, IOException{
        RandomAccessFile arch = new RandomAccessFile(ruta+"que_es.txt", "rw");
        String Linea;
        StringTokenizer ficha;
        double d, r;
        int i=0;
        
        while((Linea=arch.readLine())!= null){
            i++;
            ficha = new StringTokenizer(Linea, ", ");
            r = 0;
            while(ficha.hasMoreTokens()) {
                d = Double.valueOf(ficha.nextToken()).doubleValue();
                r += d*d;
            }
            System.out.println(i + ".- " + Math.sqrt(r));
        }
        
        arch.close();
        
    }
    
    public static void main(String args[]) throws FileNotFoundException, IOException {
        ejemplo5();
    }
}
\end{verbatim}

\section[Comandos I/O]{Uso de BufferedReader,BufferedWriter, File, FileReader, FileWriter and PrintWriter}
\section[Serialización]{Serialización de objetos usando las siguientes clases: DataOutputStream, FileInputStream, FileOutputStream, ObjectInputStream, ObjectOutputStream and Serializable}
\section{Uso de la clase  java.util.Locale}
\section{Uso de expresiones regulares}
