Icono play
Java
InputStream

Cada una de las actividades realizadas en nuestra PC despliega una secuencia de acciones y procesos dentro de la máquina, muchos de esos procesos se basan en entrada y salida de datos y manipulación de los mismos.

La entrada y salida de flujo de datos estándar en programación, es un proceso que actúa como canal de comunicación y nos permite la interacción entre nuestro programa y su entorno.

Por ejemplo, acceder a una web, llenar un formulario, subir un archivo de música a nuestra página, programar o leer un fichero de texto, son acciones que generan un flujo de datos de entrada y salida.

InputStream y su clase derivada FileInputStream

En el caso de Java, la entrada de datos está representada por la clase InputStream, y como esta es una clase abstracta, no puede ser instanciada, por lo tanto sus métodos deben ser implementados por las clases hijas.

Como ya dijimos, InputStream es una superclase abstracta de Java, esta clase nos devuelve un flujo de datos que adquiere de la lectura de un fichero, el cual es accedido byte a byte por su clase derivada FileInputStream,  que implementa los métodos de la clase padre.

Para utilizar esta superclase y su derivada debemos importarlas en la primera línea de nuestro programa:

import java.io.InputStream;
import java.io.FileInputStream;

Manejo de errores de la clase FileInputStream

Puede suceder que en el momento que se solicite acceder al fichero (por ejemplo “miarchivo.txt”) el mismo no se encuentre, esto lanzaría un error en Java del tipo FileNotFoundException, si sucediera, nuestro programa dejaría de funcionar.

Contemplando este hecho Java nos facilita el manejo de excepciones a través de distintas clases para evitar que el programa de error y se aborte.

Frente a esta situación estamos exigidos a capturar la exception para que el código siga ejecutando el resto de sentencias del programa y lo haremos con un bloque try and catch

A continuación presentamos un ejemplo de encapsulamiento con el bloque mencionado: 

try {
    InputStream fichero =  new FileInputStream(“miarchivo.txt”);
    //aquí la secuencia de órdenes a realizar, por ejemplo la lectura del fichero
} catch (FileNotFoundException e) { //aquí capturamos el error
    System.out.println("No se encuentra el fichero: " + e.getMessage());
}

Nota:e”  es la variable que va a guardar el error para mostrarlo por pantalla cuando el método .getMessage() lo solicite.

Notemos que en el código se encuentra la palabra reservada new, con ella instanciamos un objeto llamado “fichero” que recibirá los datos del archivo a leer (“miarchivo.txt''), este objeto es una instancia de InputStream.

FileInputStream nos devuelve una secuencia de bytes (array de bytes), por lo tanto debemos utilizar una variable del tipo byte que guarde ese contenido.

byte[] datos = fichero.readAllBytes();

De esta forma leemos el fichero entero y lo guardamos en la variable, esto sirve para ficheros de tamaño pequeño.

Tengamos en cuenta que .readAllBytes(), también lanza una exception y debemos obligatoriamente capturarla con otro bloque try and catch como lo hicimos con FileInputStream, tendremos entonces una encapsulación anidada y quedará de esta forma:

try {
    InputStream fichero =  new  FileInputStream("miarchivo.txt");
    try { //bloque anidado
        //aquí la secuencia de órdenes a realizar, por ejemplo la lectura del fichero
    } catch  (IOException e) { //captura del exception correspondiente a .readAllBytes()
        System.out.println("No se puede leer el fichero " + e.getMessage());
    }
}
catch (FileNotFoundException e) { //captura del exception correspondiente a FileInputStream
    System.out.println("El programa da un error porque no encuentra el fichero: " + e.getMessage());
}

Salida por pantalla en formato texto con InputStream

FileInputStream es una clase que solo puede leer datos tipo byte, por lo tanto al mostrar el resultado en pantalla solo veremos números, que son básicamente los bytes con los que estamos trabajando, si queremos verlo como texto, debemos forzar el tipo de salida a texto de esta forma:

System.out.print((char) dato);

Además para ver el contenido completo del archivo en pantalla, debemos recorrerlo con un bucle, puede ser un bucle for, que es el más tradicional o un bucle while, dependiendo de qué método usemos para acceder a la información del fichero.

Acceder a un archivo dependiendo de su tamaño con InputStream

Cuando queremos acceder a un archivo, dependiendo del tamaño del mismo, debemos saber cuál es el método más acorde y eficiente, el rendimiento de la memoria de nuestra PC se verá afectada si utilizamos el método de lectura equivocado.

Vamos a presentar dos formas, la primera para leer un archivo pequeño, la segunda para un archivo más grande.

Acceder a archivos pequeños con InputStream

A los archivos pequeños los podemos acceder con un bucle for, que al cargar todo el fichero en memoria, será más rápido sin saturar los recursos:

public static void main(String[] args) {
    try {
        InputStream fichero = new FileInputStream("miarchivo.txt");
        try {
            byte[] datos = fichero.readAllBytes();
            for (byte dato: datos) {
                System.out.print((char) dato);
            }
        } catch (IOException e) {
            System.out.println("No se puede leer el fichero " + e.getMessage());
        }
    }
    catch (FileNotFoundException e) {
        System.out.println("El programa da un error porque no encuentra el fichero: " + e.getMessage());
    }
}

Acceder a  archivos grandes con InputStream

En el caso de un archivo más grande, podemos leer carácter a carácter para no saturar la memoria del sistema, utilizando el método .read().

Tengamos en cuenta que este método al leer byte a byte, es mucho más lento que acceder al archivo leyendo grupos de bytes.

El método .read() se utiliza con un bucle while que lee carácter a carácter, mostrando uno a uno en pantalla, recordemos que para que el dato sea legible como texto debemos forzar la salida como tal:

public static void main(String[] args) {
    try {
        InputStream fichero = new FileInputStream("miarchivo.txt");
        try {
            int dato = fichero.read();
            while (dato != -1) {
                System.out.print((char) dato); //forzamos la salida convirtiendo el dato declarado como tipo int a un caracter
                 dato = fichero.read(); //importante,en cada iteración debe actualizarse la variable que nos muestra el dato
            }
        } catch (IOException e) {
            System.out.println("No se puede leer el fichero " + e.getMessage());
        }
    }
    catch (FileNotFoundException e) {
        System.out.println("El programa da un error porque no encuentra el fichero: " + e.getMessage());
    }
}

Por qué (dato !=-1)?

El método .read() devuelve -1 cuando no hay más bytes para leer en el fichero, por eso se utiliza como condición del bucle while, de este modo se le avisa al programa que debe salirse del bucle.

Ejemplo completo aplicado a leer archivos pequeños:

import java.io.FileInputStream;
import java.io.InputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class inputstream {
    public static void main(String[] args) {
        try {
            InputStream fichero = new FileInputStream("miarchivo.txt");
            try {
                byte[] datos = fichero.readAllBytes(); //declaramos el tipo de datos como byte, ya que es lo que lee FileInputStream
                for (byte dato: datos) {
                    System.out.print((char) dato); //forzamos la salida a caracter
                }
            } catch (IOException e) { //captura de la exception de readAllBytes
                System.out.println("No se puede leer el fichero " + e.getMessage());
            }
        }
        catch (FileNotFoundException e) { //captura del exception correspondiente a FileInputStream
            System.out.println("El programa da un error porque no encuentra el fichero: " + e.getMessage());
        }
    }
}

Algunos otros métodos de la clase InputStream

  • .close() Cierra el flujo de entrada y libera el sistema asociado.
  • .read(byte[] b) Lee la cantidad de bytes especificada del archivo y los almacena en el buffer b.
  • .available() Estima el número de bytes que falta leer.
¿Todavía no te has apuntado a nuestro Bootcamp?
Tenemos muchos cursos para ofrecerte y ¡TOTALMENTE GRATIS! Estos son algunos de ellos: