BufferedReader vs Scanner
En el lenguaje java hemos visto dos de las clases más usadas para lectura que son el BufferedReader y el Scanner. En resumen sabemos que el Scanner trabaja con tokens que son cadenas de caracteres que se separan mediante delimitadores que por defecto el Scanner tiene el espacio y que el BufferedReader trabaja manualmente carácter por carácter. Usted como programador seguramente las has usado alguna vez y se ha preguntado:
¿Cuál es más fácil de usar?
Para saber esto hemos elaborado el siguiente ejemplo:
Se requiere leer los siguientes valores en una sola línea, como se muestran abajo.
hola 12345 12.22
Se deberán guardar los valores en variables de tipo de dato String, int y float, a continuación se brindaran algunas soluciones para poder resolver el anterior ejemplo.
Solución sencilla con Scanner:
Código:
import java.util.Scanner; /** * * @author Luis */ public class Solucion1Scanner { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String caracteres = sc.next(); //Lectura con Scanner int entero = sc.nextInt(); float enteroFlotante = sc.nextFloat(); System.out.println("Palabra " + caracteres); System.out.println("Numero " + entero); System.out.println("Flotante " + enteroFlotante); } }Podemos observar que los métodos que tiene Scanner nos pueden apoyar en cuestión de lecturas con cualquier tipo de dato primitivo (exepto: el char), pero con el BufferedReader tenemos que arreglárnoslas para poder tener cualquier tipo de dato, aquí se brindaran dos tipos de soluciones.
Solución sencilla con BufferedReader :
Código:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /** * * @author Luis */ public class Solucion1BufferedReader { public static void main(String[] args) throws IOException{ InputStreamReader flujoEntrada = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(flujoEntrada); String[] arreglo = br.readLine().split(" "); //el metodo split Divide los strings conforme a los espacios String caracteres = arreglo[0]; int entero = Integer.parseInt(arreglo[1]); float enteroFlotante = Float.parseFloat(arreglo[2]); System.out.println("Palabra " + caracteres); System.out.println("Numero " + entero); System.out.println("Flotante " + enteroFlotante); } }
Solución compleja con BufferedReader:
Codigo:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.regex.Pattern; /** * * @author Luis */ public class Solucion2BufferedReader { public static void main(String[] args) { InputStreamReader flujoEntrada = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(flujoEntrada); try { String linea = br.readLine(); String[] arregloStrings = linea.split(" "); int numero = 0; String palabra = ""; float numeroFlotante = 0; for (int i = 0; i < arregloStrings.length; i++) { //Recorremos nuestro arreglo de strings String expresionRegular = "[a-z]+"; boolean bandera = Pattern.matches(expresionRegular, arregloStrings[i]); //El metodo matches retornara true si el string corresponde al expresion if (bandera == true) { palabra = arregloStrings[i]; // } expresionRegular = "[0-9]+"; bandera = Pattern.matches(expresionRegular, arregloStrings[i]); if (bandera == true) { numero = Integer.parseInt(arregloStrings[i]); } expresionRegular = "^[0-9]*[.][0-9]+$"; bandera = Pattern.matches(expresionRegular, arregloStrings[i]); if (bandera == true) { numeroFlotante = Float.parseFloat(arregloStrings[i]); } } System.out.println("Palabra " + numero); System.out.println("Numero " + palabra); System.out.println("Flotante " + numeroFlotante); } catch (IOException e) { System.out.println("Error"); } } }
Estas soluciones que fueron aplicadas al BufferedReader también podrán ser aplicadas con el Scanner, usted podrá elaborarlas sin problemas.
Quedo claro que en cuestión de comodidad el Scanner es amplio vencedor sobre el BufferedReader, ya que este nos hace trabajar con caracteres.
¿Cuál hace menor tiempo?
Ahora veremos quién es el mejor en tiempo con las siguientes pruebas que hemos realizado:
Primero elaboraremos un archivo de texto que será nuestra lectura por Scanner y BufferedReader, con el mismo numero de líneas y contenido de texto.
Codigo
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; /** * * @author Luis */ public class CrearArchivoPrueba { public static void main(String[] args) { InputStreamReader flujoEntrada = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(flujoEntrada); System.out.println("**Crear archivo de texto**\n" + "Ruta del archivo:"); try { String ruta = br.readLine(); System.out.println("Nombre del archivo:"); String nombre = br.readLine(); System.out.println("Texto:"); String texto = br.readLine(); System.out.println("Numero de lineas:"); int numero = Integer.parseInt(br.readLine()); System.out.println("Se ha finalizado"); crearArchivo(ruta, nombre, texto, numero); } catch (IOException e) { System.out.println("Error"); } } public static void crearArchivo(String ruta, String nombreDelArchivo, String texto, int numeroLineas) throws IOException { ArrayListlineas = new ArrayList<>(); for (int i = 0; i < numeroLineas; i++) { //Numero de lineas que seran agregadas al arraylist lineas.add(texto); } File archivo = new File(ruta + "\\" + nombreDelArchivo); /*La clase File nos permite crear un archivo de tipo txt, en el constructor le agregamos el directorio donde queremos crear el archivo*/ FileWriter archivoEscritura = new FileWriter(archivo, true); //La clase FileWriter hace que podamos escribir caracteres dentro del archivo BufferedWriter bw = new BufferedWriter(archivoEscritura); //BufferedWriter permite crear un flujo de caracteres de salida for (int i = 0; i < lineas.size(); i++) { String linea = lineas.get(i); bw.write(linea); bw.newLine(); //Salto de linea } bw.close(); // Cierra el flujo } } //
Ingresamos los datos como en el siguiente ejemplo:
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.Scanner; /** * * @author Luis */ public class Pruebas { public static void main(String[] args) { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.println("**Pruebas de BufferredRead y Scanner**\n" + "Metodos de BufferedReader:\n" + "a)readLine " + "b)nextManual\n" + "Metodos de Scanner:\n" + "c)nextLine " + "d)next"); try { char letra = (char) br.read(); long tInicial = System.currentTimeMillis(); // Para Medir el tiempo inicial switch (letra) { case 'a': pruebaReadLine("PruebaLineas.txt"); //En el constructor ponemos el nombre de nuestro txt realizado break; case 'b': pruebaNextManual("PruebaNext.txt"); break; case 'c': nextLine("PruebaLineas.txt"); break; case 'd': next("PruebaNext.txt"); break; default: System.out.println("Caracter incorrecto"); break; } long tFinal = System.currentTimeMillis() - tInicial; double promedio = (double) tFinal / 1000000; /*Realizamos la operacion de forma directa para evitar que se tome mas tiempo de esto con un contador*/ System.out.printf("%.7f", promedio); } catch (IOException e) { System.out.println("Error " + e); } } public static void pruebaReadLine(String nombreArchivo) throws IOException { BufferedReader brFileReader = new BufferedReader(new FileReader(nombreArchivo)); //La clase FileReader hace que podamos leer caracteres dentro del archivo while (brFileReader.ready()) { //Mientras que el buffer no este vacio String linea = brFileReader.readLine(); } brFileReader.close(); // Se cierra el flujo } public static void pruebaNextManual(String nombreArchivo) throws IOException { BufferedReader brFileReader = new BufferedReader(new FileReader(nombreArchivo)); while (brFileReader.ready()) { char caracter = '/'; //Se inicializa el char String palabra = ""; //Se incializa el string while (true) { caracter = (char) brFileReader.read(); //Lee un caracter palabra += caracter; if (caracter == '\n' || caracter == ' ') { // Si es salto de linea o esta vacio se rompe el ciclo break; } } } brFileReader.close(); } public static void next(String nombreDelArchivo) throws IOException { Scanner scFile = new Scanner(new FileReader(nombreDelArchivo)); while (scFile.hasNext()) { //Mientras tenga caracteres String palabra = scFile.next(); } } public static void nextLine(String nombreDelArchivo) throws IOException { Scanner scFile = new Scanner(new FileReader(nombreDelArchivo)); while (scFile.hasNextLine()) { //Mientras tenga una linea String linea = scFile.nextLine(); } } }
Metodos
|
Tiempo en milisegundos
|
readLine()
|
0.0005620
|
nextManual()
|
0.0006850
|
nextLine()
|
0.0025680
|
next()
|
0.0015290
|
Como se pudo observar el ganador en esta prueba fue el uso de la clase BufferedReader respecto a los métodos utilizados, podemos decir que si queremos elaborar un código optimo con mejor tiempo recomendamos usar esta clase.
¿Cuál es mejor?
Elegir una ganadora es muy complicado porque cada una tiene sus propias ventajas unas sobre otras, el programador deberá saber que es lo más conveniente para utilizar en su código por ejemplo si se quiere trabajar con una lectura de línea de forma manual para realizar trabajos sencillos se podrá utilizar el BufferedReader o bien queremos usar una manera más automatizada se usara el Scanner, usted tendrá la decisión de escoger la que crea más conveniente para su caso.