es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Spring Boot java: Procesar/Comparar líneas de un archivo muy grande.

Tengo esta aplicación en la que proceso un archivo muy grande, extraigo las líneas que tienen los mismos primeros 5 caracteres (a esto lo llamo currentlineId), las uso para crear un objeto y hacer algo con él, por ejemplo, un ejemplo del contenido del archivo:

AZDFS12345678998765432345678
AZDFS09876545432345678987654
AZDFS34568987654567890987654
AZDFS12345670987654345678998
AZDFS12345098734567765123456
// las líneas anteriores tienen los mismos primeros 5 caracteres, crean el objeto Object1.

FGHJUY121324
FGHJUY089909
FGHJUYTTUTUU
// lo mismo para las líneas anteriores, crean el objeto Object2.

NB: las líneas siempre estarán en un orden en el que las líneas con los mismos primeros 5 caracteres siempre estarán juntas (arriba/abajo una de la otra), así que no tendré líneas por todas partes.

Mi código de función actual:

 private void processScpFile(File file) {
    LOGGER.info("Procesando Archivo: {} ", file.getName());

    try (var br = new BufferedReader(new FileReader(file))) {

        String currentLine;
        String lastLineId = null;
        List<string> similarLineIdsList = new ArrayList<>();

        while ((currentLine = br.readLine()) != null) {

            if (StringUtils.isEmpty(lastLineId)) {
                lastLineId = currentLine.substring(0,5);
            }

            if (lastLineId.equals(currentLine.substring(0,5))) {
                similarLineIdsList.add(currentLine);
            }

            else if (!lastLineId.equals(currentLine.substring(0,5))) {

                doSomethinsWithTheList(similarLineIdsList);

                similarLineIdsList.clear();

                similarLineIdsList.add(currentLine);
                lastLineId= currentLine.substring(0,5);
            }
        }

        doSomethinsWithTheList(similarLineIdsList);

    }
    catch (IOException e) {
        LOGGER.error("No se pudo leer el archivo, {}", e.getMessage(), e);
    }
}

Ahora esto ha funcionado bien hasta ahora, pero en adelante debo procesar archivos donde por ejemplo tendría más de 100k líneas con los mismos primeros 5 caracteres, lo que hace que este proceso sea muy lento.
Por favor, ¿tienes alguna sugerencia sobre cómo hacer que este proceso sea más rápido? Gracias.

Edit: solo para ser preciso, es la generación de la lista con los mismos primeros 5 caracteres lo que es más lento a medida que aumenta el número de líneas similares.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Una sugerencia para acelerar este proceso sería utilizar el procesamiento paralelo. Puedes dividir el archivo en fragmentos más pequeños y procesar cada fragmento de forma concurrente. Esto se puede lograr utilizando el API de Stream de Java 8 y su función paralela.

    Aquí tienes un ejemplo de código que utiliza streams paralelos para procesar el archivo:

    private void processScpFile(File file) {
        LOGGER.info("Procesando archivo: {}", file.getName());
    
        try (var br = new BufferedReader(new FileReader(file))) {
    
            Map<string,></string,><string>> lineIdsMap = br.lines()
                    .parallel() //habilitar el procesamiento paralelo
                    .collect(Collectors.groupingBy(line -> line.substring(0, 5)));
    
            lineIdsMap.values()
                    .parallelStream() //habilitar el procesamiento paralelo
                    .forEach(this::doSomethingWithTheList);
    
        } catch (IOException e) {
            LOGGER.error("No se pudo leer el archivo, {}", e.getMessage(), e);
        }
    }
    
    private void doSomethingWithTheList(List<string> similarLineIdsList) {
        //procesa la lista aquí
    }
    

    En este código, utilizamos el método lines() del BufferedReader para obtener un stream de líneas del archivo. Luego habilitamos el procesamiento paralelo utilizando el método parallel(). Agrupamos las líneas en función de sus primeros 5 caracteres utilizando el recolector groupingBy(), que devuelve un mapa donde las claves son los primeros 5 caracteres y los valores son listas de líneas con la misma clave.

    A continuación, utilizamos el método values() del mapa para obtener un stream de las listas y habilitamos el procesamiento paralelo en ellas utilizando parallelStream(). Pasamos cada lista al método doSomethingWithTheList() para procesarla.

    Ten en cuenta que el procesamiento paralelo funciona mejor cuando la operación de procesamiento está limitada por la CPU y no implica llamadas de entrada/salida o de red. Si el método doSomethingWithTheList() implica llamadas de entrada/salida o de red, es posible que no veas una mejora significativa en el rendimiento con el procesamiento paralelo.

Comments are closed.