Fundamentos de Java — Parte III
Scanner y manejo de archivos
La clase java.util.Scanner es muy útil para procesar flujos de datos llamados Streams, un flujo de datos es por ejemplo, la entrada y salida estándar que comunmente es el teclado y la terminal respectivamente, sin embargo los archivos también generan flujos de datos. La clase Scanner nos permite construir un objeto que trabaja directamente sobre el stream permitiendonos leer números, cadenas y bytes. Para crear una instancia debemos hacer Scanner sc = new Scanner(stream)
donde sc
es un nombre cualquiera para nuestro objeto Scanner y stream
representa un flujo de datos de entrada como puede ser System.in
(la entrada estándar o el teclado) o un InputStream en general como un FileInputStream. En el siguiente código podemos observar el uso de Scanner para leer dos números desde el teclaso y mostrar su suma en la pantalla.
Observa que imprimimos un mensaje antes de leer el número y leemos el número mediante sc.nextInt()
. Si quisieramos leer otros tipos de datos podemos usar nextFloat()
, nextDouble()
o nextLine()
el último devuelve una cadena de texto de tipo String. No olvides importar el paquete import java.util.Scanner
para que reconozca la clase.
Abrir un archivo
Para abrir un archivo utilizaremos la clase FileInputStream, la cual nos devuelve un InputStream que representa un flujo de datos de entrada que podemos utilizar con Scanner. El InputStream puede generar excepciones si no puede leer el archivo o problemas similares, por lo que deberemos hacer que nuestro método pueda fallar agregando throws IOException
a nuestra declaración. En el siguiente ejemplo se muestra como abrir un archivo de texto plano llamado datos.txt
el cual se supone es accesible desde nuestro programa (se encuentra en la misma ubicación o se escribe la ruta completa). Entonces lo primero que se hace es agregar la librería import java.io.FileInputStream
, luego hay que marcar el método main como public static void main(String[] args) throws new IOException { ... }
lo cual permitirá propagar la excepción (y evitar el uso de try-catch). Finalmente podemos recorrer byte por byte con un ciclo while usando in.read()
para imprimir el byte en la terminal.
Observa que se han importado java.io.FileInputStream y java.io.IOException, las cuales nos permiten utilizar las clases correspondientes, luego se ha marcado el método main con throws IOException para permitir propagar el error, entonces se crea la instancia in
mediente FileInputStream y el nombre del archivo. Una vez abierto el flujo de datos procedemos a crear una variable b
que va a retener cada byte leído, usando while ((b = in.read()) != -1)
declaramos un ciclo while
el cual va a repetir el bloque de código mientras la condición sea verdadera, en este caso la condición es “Asigna a b el siguiente byte leído del flujo de entrada in, luego comprueba si el byte es distinto de -1”. Entonces mientras el byte leído no sea -1, el programa va a imprimir el valor del byte y un espacio. Finalmente observa que cerramos el flujo antes de terminar con in.close()
.
Abrir un archivo y leer sus datos con Scanner
Leer los bytes de un archivo no es lo más útil para trabajar un archivo de números o texto. Por ejemplo, supongamos que tenemos el siguiente archivo de datos:
En el archivo numeros.txt
hemos colocado en la primer línea el número 5 y en la segunda línea hemos dispuesto 5 números separados por coma. Si quisieramos leer los valores podemos hacerloa través de un Scanner como se muestra en el ejemplo de abajo.
Observa que abrimos el flujo para el archivo numeros.txt
, luego creamos un Scanner sobre el flujo, después leemos el primer número del flujo utilizando sc.nextInt()
, este buscará el siguiente número y lo devolverá (en este caso el número 5, es decir, n vale 5). Luego imprimimos la leyenda Leyendo 5 números
(observa que se reemplaza n). Seguido, creamos un ciclo con n iteraciones (de 0 a n-1 hay n iteraciones), dentro del ciclo leemos el siguiente número en el flujo usando el Scanner, en la primera iteración será el 10. Aquí puedes observar que no importa que los números estén en distintas líneas o separados por uno o varios espacios. Finalmente debemos cerrar el Scanner con sc.close()
para que este se encargue de cerrar el archivo.
Con esto ya puedes manipular archivos de forma fácil, ahora debes profundizar tus conocimientos resolviendo los siguientes problemas.
Problema 1. Crear un programa que cuente el número de bytes en un archivo.
Problema 2. Crear un programa que imprima cada byte invertido (255 menos el valor del byte).
Problema 3. Modifica el archivo
numeros.txt
para poner 20 números en lugar de 5 (coloca 20 números que quieras).Problema 4. Modifica el programa anterior para que calcule la suma de los números.
Problema 5. Modifica el programa anterior para que además calcule el promedio de los números.
Problema 6. Modifica el programa anterior para que además muestre cuál es el número mayor.
Problema 7. Modifica el programa anterior para que además muestre cuál es el número menor.
Problema 8. Crea un archivo con al menos 5 líneas de texto y crea un programa que imprima línea por línea y su longitud. Hint. Utiliza el método
sc.hasNextLine()
para saber si hay una siguiente línea,sc.nextLine()
para leer la siguiente línea y el ciclowhile (sc.hasNextLine())
para que repita la lectura de la línea para cada línea del archivo. La longitud de una línea se obtiene conlinea.length()
.