8 мая 2022
Давайте сгенерируем строку из случайных символов на Java и затем сохраним её в текстовый файл. На этом примере рассмотрим несколько вариантов сохранения. Строка должна быть очень большой (более 100 миллионов символов), чтобы мы могли легко заметить разницу во времени, которое требуется на сохранение файла.
Приведу код метода, который в цикле генерирует случайные UUID и формирует результирующую строку, в которой эти UUID разделены символом перевода строки.
Для формирования результирующей строки используем StringBuilder, который не вызовет накладных расходов при большом количестве конкатенаций строк в цикле. Чтобы ставить правильный символ перевода строки, который зависит от вашей ОС, используем метод lineSeparator(). Каждый UUID имеет фиксированную длину, равную 36 символам.
Один из самых простых способов записать данные в текстовый файл – это использовать класс FileWriter. Метод принимает на вход экземпляр класса File и сами данные в виде строки. Данные пишем с помощью метода write().
Обратите внимание, что FileWriter нужно обязательно инициализировать в конструкции try-with-resources, который автоматически освободит ресурс, связанный с этим файлом, при выходе из этого блока. Иначе пришлось бы явно вызывать метод close(). Для удобства перехватываем все исключения и оборачиваем их в RuntimeException, чтобы не прописывать их в сигнатуре метода.
Данный метод сохраняет текстовый файл размером 111 МБ на моём ноуте с SSD примерно за 300 миллисекунд.
Этот метод можно значительно ускорить, добавив буферизацию потока. Для этого «обернём» FileWriter в BufferedWriter. Он также должен быть в секции инициализации try-with-resources.
Метод write() будем вызывать уже у буферизованного потока. Когда выйдем из блока try, JVM автоматически закроет BufferedWriter, а заодно с ним и FileWriter, поскольку один «обёрнут» в другой.
Данный метод сохраняет тот же файл размером 111 МБ примерно за 170 миллисекунд. То есть буферизация потока ускоряет запись файла почти в 2 раза!
Запись можно ещё немного ускорить, если использовать статический класс Files из пакета nio (неблокирующий ввод-вывод). В нём есть метод writeString(), который принимает экземпляр класса Path (его получаем из File), саму строку для записи и параметры открытия файла (мы здесь всегда создаём файл заново, поэтому CREATE).
Данный метод сохраняет файл размером в 111 МБ в среднем за 145 миллисекунд, то есть ещё чуть быстрее.
Как видите, даже огромные текстовые файлы по 100 МБ Java сохраняет менее, чем за секунду. Если вы работаете с маленькими файлами, разницы между рассмотренными реализациями почти нет. Однако быстрее всех оказался неблокирующий Files.writeString(). Если он вам по каким-то причинам не подходит, то обязательно используйте BufferedWriter.
Kotlin, Java, Spring, Spring Boot, Spring Data, SQL, PostgreSQL, Oracle, Linux, Hibernate, Collections, Stream API, многопоточность, файлы, Nginx, Apache, maven, gradle, JUnit, YouTube, новости, руководство, ООП, алгоритмы, головоломки, rest, GraphQL, Excel, XML, json, yaml.