Logo DIE

Manejo de Archivos

Unidad de Apoyo para el Aprendizaje

Iniciar

Introducción


Los programas necesitan comunicarse con su entorno, tanto para obtener datos e información que deben procesar, como para devolver los resultados obtenidos.

El manejo de archivos se realiza a través de streams o flujos de datos desde una fuente hacia un repositorio. La fuente que inicia el flujo de datos se conoce como flujo de datos de entrada; el repositorio que termina el flujo de datos se denomina flujo de datos de salida. Es decir, tanto la fuente como el repositorio son nodos de flujos de datos.



Diagrama de bloques



Además, el manejo de archivos permite persistir los datos, es decir, conservarlos de manera permanente en un medio de almacenamiento externo.

Recuerda que un programa se ejecuta en la memoria principal de la computadora, de modo que cuando se acaba el programa los datos de la memoria principal se pierden. Sin embargo, si se requiere que la información creada en un programa se guarde de forma permanente se debe almacenar en la memoria secundaria (disco duro) en forma de archivo.



Implementar el intercambio de datos de lectura y escritura entre fuentes externas (como archivos o entrada y salida estándar) y un programa en un lenguaje orientado a objetos, para almacenar la información de forma permanente en un medio de almacenamiento secundario.

Archivos


Un archivo debe tener un nombre único dentro de la carpeta que lo contiene. Normalmente, el nombre de un archivo contiene un sufijo (extensión) que permite identificar el tipo del archivo.

Flujos de datos

Las entradas y las salidas de datos en Java se manejan mediante streams (flujos de datos). Un stream es una conexión entre el programa y la fuente (lectura) o el destino (escritura) de los datos. La información se traslada en serie a través de esta conexión.

En Java existen cuatro jerarquías de clases relacionadas con los flujos de entrada y salida de datos.



Flujo de bytes


Flujo de caracteres



Todas las clases de Java relacionadas con la entrada y salida se agrupan en el paquete java.io.



Clase File

La clase File permite manejar archivos o carpetas, es decir, crear y borrarlos, entre otras funciones.

Ejemplo. Programa que crea un archivo de texto.

import java.io.File;
import java.io.IOException;

public class CreaArchivo {
        public static void main(String [] args) {

                try {
                        File file = new File("file.txt");
                        System.out.println("Existe? " + file.exists());
                        boolean wasCreated = file.createNewFile();
                        System.out.println("Se creó? " + wasCreated);
                        System.out.println("Existe? " + file.exists());
                } catch(IOException e) {
                        System.out.println(e.getMessage());
                }
        }
}



FileOutputStream

La clase FileOutputStream permite crear y escribir un flujo de bytes en un archivo de texto plano. Esta clase hereda de la clase OutputStream. Sus constructores más comunes son:

FileOutputStream (String nombre)

FileOutputStream (String nombre, boolean añadir)

FileOutputStream (File archivo)

Ejemplo. Escritura usando FileOutputStream

import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamClass {
        public static void main (String [] args){
                FileOutputStream fos = null;
                byte[] buffer = new byte[81];
                int nBytes;
                try {
                        System.out.println("Escribir el texto a guardar en el archivo:");
                        nBytes = System.in.read(buffer);
                        fos = new FileOutputStream("fos.txt");
                        fos.write(buffer,0,nBytes);
                } catch (IOException ioe){
                         System.out.println("Error: " + ioe.toString());
                } finally {
                        try {
                                if (fos != null)
                                        fos.close();
                        } catch (IOException ioe){
                                System.out.println("Error : " + ioe.toString());
                        }
                }
        }
}

En el ejemplo anterior se define un arreglo llamado buffer de 81 bytes, donde se va a almacenar lo que se capture del teclado (máximo 81 bytes).

Después se crea el flujo de bytes mediante la clase FileOutputStream y se envía al archivo de nombre fos.txt.

Al final, se hace uso del método write de la clase FileOutputStream para escribir los datos del buffer en el archivo.

El método write es un método sobrecargado. Otros usos de éste se pueden consultar en el API de Java.

Por otra parte, es una buena práctica de programación cerrar el flujo de datos al final de la ejecución del programa. Debido a que la escritura de datos puede fallar, el bloque finally es el mejor lugar para cerrar la conexión.



FileInputStream

FileInputStream permite leer flujos de bytes desde un archivo de texto plano. Hereda de la clase InputStream. Sus constructores más comunes son:

FileInputStream(String nombre)

FileInputStream(File archivo)

Ejemplo

import java.io.FileInputStream;
import java.io.IOException;

public class FileInputStreamClass {
         public static void main (String [] args){
                FileInputStream fis = null;
        byte[] buffer = new byte[81];
        int nbytes;
        try {
                        fis = new FileInputStream("FileInputStreamClass.java");
                nbytes = fis.read(buffer, 0, 81);
                while (nbytes != -1) {
                        String text = new String(buffer, 0, nbytes);
                        System.out.println(text);
                        nbytes = fis.read(buffer, 0, 81);
                        }
        }
        catch (IOException ioe) {
                        System.out.println("Error: " + ioe.toString());
        } finally {
                try {
                        if (fis != null) fis.close();
                } catch (IOException ioe) {
                System.out.println("Error al cerrar el archivo.");
                }
             }
          }
        }

En el ejemplo anterior se define un flujo que va a leer datos desde una fuente (archivo) definida en el programa; si no existe el archivo se genera una excepción.

También se crea un buffer de 81 bytes. El objeto FileInputStream lee el texto desde el archivo y lo almacena en el buffer creado. Se lee el archivo hasta que se terminen los caracteres de éste o hasta que se llene el buffer (desde la posición 0 hasta la 81), lo que ocurra primero.

El método read devuelve el número de bytes leídos o -1, si se finalizó la lectura del archivo.

La clase FileWriter hereda de Writer y permite escribir un flujo de caracteres en un archivo de texto plano.

La clase BufferedWriter también deriva de la clase Writer y permite crear un buffer para realizar una escritura eficiente de caracteres desde la aplicación hacia el archivo destino.

La clase PrintWriter, que también deriva de Writer, permite escribir de forma sencilla en un archivo de texto plano. Posee los métodos print y println, idénticos a los de System.out, y el método close( ), el cual cierra el stream de datos.

Las clases Reader se utilizan para obtener los caracteres ingresados desde una fuente. La clase FileReader hereda de Reader y permite leer flujos de caracteres de un archivo de texto plano.





InputStreamReader


InputStreamReader es una clase que deriva de Reader que convierte los streams de bytes a streams de caracteres. System.in es el objeto de la clase InputStream, el cual recibe datos desde la entrada estándar del sistema (el teclado).



BufferedReader

La clase BufferedReader, que también deriva de la clase Reader, crea un buffer para realizar una lectura eficiente de caracteres. Dispone del método readLine que permite leer una línea de texto y tiene como valor de retorno un String.

Ejemplo: Lectura usando FileReader

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class FileReaderClass{
        public static void main (String [] escribir){
                String texto = "";
                try {
                        BufferedReader br;
                        FileReader fr = new FileReader("FileReaderClass.java");
                        br = new BufferedReader(fr);
                        System.out.println("El texto contenido en el archivo es:");
                        String line = br.readLine();
                        while (line != null ) {
                                System.out.println(line);
                                line = br.readLine();
                        }
                fr.close();
                }
                catch (IOException ioe) {
                        System.out.println("\n\nError al abrir o leer el archivo:");
                        ioe.printStackTrace();
                } catch (Exception e) {
                        System.out.println("\n\nError al leer de teclado:");
                         e.printStackTrace();
                }
        }
}

Escritura usando FileWriter

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.IOException;

public class FilePrintWriter{
        public static void main (String [] leer){
                String texto = "";
                FileWriter fw = null;
                BufferedWriter bw = null;
                PrintWriter salida = null;
                try{
                        BufferedReader br;
                        br = new BufferedReader(new InputStreamReader(
System.in));
                        System.out.println("Escribir texto:");
                        texto = br.readLine();
                        fw = new FileWriter("print.txt");
                        bw = new BufferedWriter(fw);
                        salida = new PrintWriter(bw);
                        salida.println(texto);
                }
                        catch (IOException ioe){
                                System.out.println("\n\nError al abrir o guardar el archivo:");
                                 ioe.printStackTrace();
                } catch (Exception e){
                        System.out.println("\n\nError al leer de teclado:");
                        e.printStackTrace();
                } finally {
                        try {
                                if (salida != null)
                                        salida.close();
                        } catch (Exception e){
                                System.out.println("Error : " + e.toString());
                        }
                }
        }
}

Lectura de teclado

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class BufferedReaderClass {
        public static void main (String [] args){
                try {
                        String text = "";
                        BufferedReader br;
                        br = new BufferedReader(new InputStreamReader(
System.in));
                        System.out.println("Escriba el texto deseado:");
                        text = br.readLine();
                        System.out.println("El texto escrito fue: " + text);
                } catch (IOException ioe){
                        System.out.println("Error al leer caracteres: \n" + ioe);
                }
        }
}



StringTokenizer

La clase StringTokenizer permite separar una cadena de texto con palabras (espacios) o con algún otro carácter. La clase StringTokenizer pertenece al paquete java.util.

Ejemplo

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class StringTokenizerClass {
        public static void main (String [] leer){
                String text = "";
                try{
                        BufferedReader br;
                        br = new BufferedReader(new InputStreamReader(
System.in));
                        System.out.println("Escribir texto:");
                        text = br.readLine();
                        System.out.println("\n\nEl texto separado por espacios es:");
// Se separa el texto por espacios (defecto)
                        StringTokenizer st = new StringTokenizer(text);
                        while(st.hasMoreTokens()) {
                                System.out.println(st.nextToken());
                        }
br.readLine();
                        System.out.println("\n\nEl texto completo es:");
                        System.out.println(text);
                } catch (Exception e){
                        System.out.println("\n\nError al leer de teclado:");
                        e.printStackTrace();
                }
         }
}



Scanner

La clase Scanner permite leer flujos de bytes desde la entrada estándar, pero también puede hacerlo desde otra fuente. Pertenece al paquete java.util.

Los métodos principales de esta clase son next( ) y hasNext( ). El método next( ) obtiene el siguiente elemento del flujo de datos. Mientras que el método hasNext( ) verifica si el flujo de datos todavía posee elementos, en caso afirmativo regresa true, de lo contrario retorna false. El delimitador de la clase Scanner (para obtener el siguiente elemento), por defecto, es el espacio en blanco; aunque es posible cambiar el delimitador utilizando el método useDelimiter que recibe como parámetro el delimitador (en forma de String).

Ejemplo

import java.util.Scanner;

public class ScannerClass {
         public static void main(String [] args) {
                 try {
                        String text = "";
                        Scanner s = new Scanner(System.in);
                        do {
                                text = s.nextLine();
                                System.out.println(text);
                        } while (!text.equals("au revoir"));
                        s.close();
                } catch (Exception e){
                        e.printStackTrace();
                }
         }
}



Console

La clase Console permite recibir flujos de datos desde la línea de comandos (entrada estándar). Se encuentra dentro del paquete java.io. Entre los métodos importantes que posee se encuentran:

readLine( ) Lee una cadena de caracteres hasta que encuentra el salto de línea (enter).

readPassword( ) Lee una cadena de caracteres hasta que encuentra el salto de línea (enter), ocultando los caracteres como lo hace el sistema operativo que se utilice.

Ejemplo

import java.io.Console;
public class ConsoleClass {
        public static void main(String [] args){
                Console con = System.console();
                System.out.print("Usuario: ");
                String user = con.readLine();
                System.out.print("Contraseña: ");
                char [] pass = con.readPassword();

                System.out.println("Los datos ingresados son:");
                System.out.println(user);
                System.out.println(pass);
         }
}

ícono

Actividad. Grupo con un profesor y varios alumnos

El manejo de archivos es una tarea primordial en todo lenguaje de programación, ya que permite guardar información importante generada en la ejecución del programa en un medio no volátil como un archivo de texto; ya que la mayoría de las ocasiones se necesita que la información generada persista (permanezca) en alguna base de datos o archivo de texto para su reutilización en un futuro o para fines de auditoria.

ícono

Autoevaluación. Jerarquía de clases de Java para el manejo de archivos

Java posee una jerarquía específica de clases para el manejo de archivos. Es posible manejar los datos en forma de bytes o en forma de caracteres. Cuando se implementa un programa es útil reconocer la forma en la que se almacena la información, porque es la misma manera en la que debe recuperarse. La idea de esta autoevaluación es validar que puedes reconocer las diferentes jerarquías de clases que tiene Java para el manejo de archivos.


Fuentes de información

Dean, J. y Dean, R. (2009). Introducción a la programación con Java. McGraw-Hill.

Martín, A. (2008). Programador certificado Java 2 (2.a ed.). Alfaomega Grupo Editor.

Sierra, K. y Bates, B. (2008). SCJP Sun Certified Programmer for Java 6 Study Guide. McGraw-Hill.


Cómo citar


Solano, J. A. (2020). Manejo de archivos. Unidades de Apoyo para el Aprendizaje. CUAIEED/Facultad de Ingeniería-UNAM. (Vínculo)