Ответ
Задача: Оптимизация обработки больших CSV-файлов (1ГБ+) в Spring Boot приложении для избежания OutOfMemoryError.
Исходная проблема: Использовался BufferedReader с загрузкой всех строк в List<String>, что приводило к исчерпанию heap-памяти.
Решение: Переход на потоковую обработку с использованием Java Stream API, что позволило обрабатывать данные чанками без полной загрузки в память.
Ключевые шаги реализации:
- Потоковое чтение:
Files.lines()для построчного чтения файла. - Пропуск заголовка и парсинг:
public void processLargeFile(String filePath) throws IOException { try (Stream<String> lines = Files.lines(Paths.get(filePath), StandardCharsets.UTF_8)) { lines .skip(1) // Пропускаем строку заголовка .map(line -> line.split(",")) // Парсим CSV .forEach(this::processRow); // Обрабатываем каждую строку } } - Оптимизация (пакетная обработка): Для снижения нагрузки на БД добавили батчинг:
List<Entity> batch = new ArrayList<>(BATCH_SIZE); lines.forEach(row -> { batch.add(toEntity(row)); if (batch.size() >= BATCH_SIZE) { repository.saveAll(batch); batch.clear(); } }); if (!batch.isEmpty()) repository.saveAll(batch);
Результат:
- Потребление памяти снизилось с ~4 ГБ до стабильных ~200 МБ.
- Время обработки сократилось на 40% за счет эффективного использования ресурсов.
- Приложение стало стабильно работать с файлами любого размера.
Вывод: Для работы с большими данными в Java критически важно использовать потоковые и ленивые модели обработки, избегая загрузки всего датасета в память.