Leer un archivo línea por línea en Java

    En Ciencias de la Computación, un archivo es un recurso que se utiliza para registrar datos discretamente en el dispositivo de almacenamiento de una computadora. En Java, un recurso suele ser un objeto que implementa el AutoCloseable interfaz.

    La lectura de archivos y recursos tiene muchos usos:

    • Estad√≠sticas, an√°lisis e informes
    • Machine Learning
    • Manejo de registros o archivos de texto grandes

    A veces, estos archivos pueden ser absurdamente grandes, con gigabytes o terabytes almacenados, y leerlos en su totalidad es ineficaz.

    Poder leer un archivo l√≠nea por l√≠nea nos da la capacidad de buscar solo la informaci√≥n relevante y detener la b√ļsqueda una vez que hayamos encontrado lo que estamos buscando. Tambi√©n nos permite dividir los datos en partes l√≥gicas, como si el archivo tuviera formato CSV.

    Hay algunas opciones diferentes para elegir cuando necesita leer un archivo línea por línea.

    Esc√°ner

    Una de las formas más fáciles de leer un archivo línea por línea en Java podría implementarse utilizando el Escáner clase. Un escáner divide su entrada en tokens usando un patrón delimitador, que en nuestro caso es el carácter de nueva línea:

    Scanner scanner = new Scanner(new File("filename"));
    while (scanner.hasNextLine()) {
       String line = scanner.nextLine();
       // process the line
    }
    

    los hasNextLine() devuelve el m√©todo true si hay otra l√≠nea en la entrada de este esc√°ner, pero el esc√°ner en s√≠ no avanza m√°s all√° de ninguna entrada ni lee ning√ļn dato en este punto.

    Para leer la línea y seguir adelante, debemos usar el nextLine() método. Este método hace avanzar el escáner más allá de la línea actual y devuelve la entrada que no se alcanzó inicialmente. Este método devuelve el resto de la línea actual, excluyendo cualquier separador de línea al final de la línea. La posición de lectura se establece al principio de la siguiente línea, que se leerá y devolverá al llamar al método nuevamente.

    Dado que este m√©todo contin√ļa buscando a trav√©s de la entrada buscando un separador de l√≠nea, puede almacenar en b√ļfer toda la entrada mientras busca el final de la l√≠nea si no hay separadores de l√≠nea presentes.

    Lector en b√ļfer

    los BufferedReader La clase representa una forma eficiente de leer los caracteres, matrices y líneas de un flujo de entrada de caracteres.

    Como se describe en la denominaci√≥n, esta clase usa un b√ļfer. La cantidad predeterminada de datos que se almacenan en b√ļfer es de 8192 bytes, pero se puede establecer en un tama√Īo personalizado por razones de rendimiento:

    BufferedReader br = new BufferedReader(new FileReader(file), bufferSize);
    

    El archivo, o más bien una instancia de un File clase, no es una fuente de datos apropiada para el BufferedReader, entonces necesitamos usar un FileReader, que se extiende InputStreamReader. Es una clase de conveniencia para leer información de archivos de texto y no es necesariamente adecuada para leer un flujo de bytes sin procesar:

    try (BufferedReader br = new BufferedReader(new FileReader(file))) {
        String line;
        while ((line = br.readLine()) != null) {
           // process the line
        }
    }
    

    La inicializaci√≥n de un lector con b√ļfer se escribi√≥ utilizando la sintaxis try-with-resources, espec√≠fica de Java 7 o superior. Si est√° utilizando una versi√≥n anterior, debe inicializar el br variable antes de la try declaraci√≥n y ci√©rrelo en el finally bloquear.

    A continuación, se muestra un ejemplo del código anterior sin la sintaxis try-with-resources:

    BufferedReader br = new BufferedReader(new FileReader(file));
    try {
        String line;
        while ((line = br.readLine()) != null) {
           // process the line
        }
    } finally {
        br.close();
    }
    

    El código recorrerá las líneas del archivo proporcionado y se detendrá cuando se encuentre con el null línea, que es el final del archivo.

    No se confunda como el null no es igual a una línea vacía y el archivo se leerá hasta el final.

    El método de las líneas

    UN BufferedReader la clase también tiene un lines método que devuelve un Stream. Esta secuencia contiene líneas que fueron leídas por el BufferedReader, como sus elementos.

    Puede convertir f√°cilmente esta secuencia en una lista si necesita:

    List<String> list = new ArrayList<>();
    
    try (BufferedReader br = new BufferedReader(new FileReader(file))) {
        list = br.lines().collect(Collectors.toList());    
    }
    

    Leer esta lista es lo mismo que leer una secuencia, que se tratan en la siguiente sección:

    list.forEach(System.out::println);
    

    Secuencias de Java 8

    Si ya est√° familiarizado con Java 8 Corrientes, puede usarlos como una alternativa m√°s limpia al ciclo heredado:

    try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
        stream.forEach(System.out::println);
    }
    

    Aquí estamos usando la sintaxis try-with-resources una vez más, inicializando un flujo de líneas con el Files.lines() método auxiliar estático. los System.out::println La referencia de método se usa para propósitos de demostración, y debe reemplazarla con cualquier código que esté usando para procesar sus líneas de texto.

    Adem√°s de una API limpia, las transmisiones son muy √ļtiles cuando desea aplicar m√ļltiples operaciones a los datos o filtrar algo.

    Supongamos que tenemos una tarea para imprimir todas las l√≠neas que se encuentran en un archivo de texto dado y terminan con el car√°cter “/”. Las l√≠neas deben transformarse a may√ļsculas y ordenarse alfab√©ticamente.

    Al modificar nuestro ejemplo inicial de “Streams API” obtendremos una implementaci√≥n muy limpia:

    try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
        stream
            .filter(s -> s.endswith("/"))
            .sorted()
            .map(String::toUpperCase)
            .forEach(System.out::println);
    }
    

    los filter() El m√©todo devuelve una secuencia que consta de los elementos de esta secuencia que coinciden con el predicado dado. En nuestro caso, solo dejamos aquellos que terminan con “/”.

    los map() El método devuelve una secuencia que consta de los resultados de aplicar la función dada a los elementos de esta secuencia.

    los toUpperCase() método de un String La clase nos ayuda a lograr el resultado deseado y se utiliza aquí como referencia de método, al igual que la println llamada de nuestro ejemplo anterior.

    los sorted() El m√©todo devuelve una secuencia que consta de los elementos de esta secuencia, ordenados seg√ļn el orden natural. Tambi√©n puede proporcionar una Comparator, y en ese caso la clasificaci√≥n se realizar√° de acuerdo con √©l.

    Si bien el orden de las operaciones podría cambiarse para filter(), sorted()y map() métodos, el forEach() siempre debe colocarse al final, ya que es una operación de terminal. Vuelve void y de hecho, nada se le puede encadenar más.

    Apache Commons

    Si ya estás usando Apache Commons en su proyecto, es posible que desee utilizar el ayudante que lee todas las líneas de un archivo en un List<String>:

    List<String> lines = FileUtils.readLines(file, "UTF-8");
    for (String line: lines) {
        // process the line
    }
    

    Recuerde que este enfoque lee todas las líneas del archivo en el lines lista y sólo entonces la ejecución de la for comienza el bucle. Puede llevar una cantidad significativa de tiempo y debe pensarlo dos veces antes de usarlo en archivos de texto grandes.

    Conclusión

    Hay varias formas de leer un archivo l√≠nea por l√≠nea en Java, y la selecci√≥n del enfoque apropiado es decisi√≥n del programador. Debe pensar en el tama√Īo de los archivos que planea procesar, los requisitos de rendimiento, el estilo del c√≥digo y las bibliotecas que ya est√°n en el proyecto. Aseg√ļrese de probar en algunos casos de esquina, como archivos enormes, vac√≠os o inexistentes, y estar√° listo para usar cualquiera de los ejemplos proporcionados.

     

    Etiquetas:

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *