Запись в файл Java: чистый код против производительности

При работе над корпоративным приложением иногда возникает необходимость записывать текстовые или двоичные данные в файлы на Java, например, записывать созданные пользователем отчеты в файловую систему.

Хотя существует множество способов записи файлов в Java, давайте быстро рассмотрим некоторые из них, чтобы иметь возможность быстро воспользоваться ими при необходимости.

 Содержимое строки = "какой-то текст";// Ява 11Files.writeString(Path.of("demo.txt"), content);// Использование класса FilesФайлы.write(Path.of("demo.txt"), content.getBytes());// Использование BufferedWriterпопробуйте(BufferedWriter writer = new BufferedWriter(new FileWriter(filePath.toFile()))) {писатель.запись(контент);}// Использование FileWritertry(FileWriter fileWriter = new FileWriter(Path.of("demo.txt").toFile())){fileWriter.write(контент);}// Запись в двоичный файлtry(FileOutputStream outputStream = new FileOutputStream(Path.of("demo.txt").toFile())){byte[] strToBytes = content.getBytes();outputStream.write(strToBytes);}

1. Использование Files.writeString() – Java 11

Начиная с Java 11, метод Files.writeString() предлагает удобный способ записи текста в файл. Он принимает параметр Path и строку, упрощая процесс записи текстового содержимого в однострочном операторе.

  • Как следует из названия, метод writeString() используется для записи символьных/текстовых данных в файлы.
  • Все символы пишутся как есть, включая разделители строк. Дополнительные символы не добавляются.
  • По умолчанию используется кодировка символов UTF-8.
  • Он выдает исключение IOException, если при записи или создании файла возникает ошибка ввода-вывода или если текст не может быть закодирован с использованием указанного набора символов.
Path filePath = Path.of("demo.txt");String content = "hello world !!";Files.writeString(filePath, content);

2. Запись в файл с помощью Files.write()

Класс Files — это еще один метод write(), начиная с Java 7, и он работает аналогично writeString(). Он принимает Path и массив байтов в качестве параметров.

Метод write() подходит для записи двоичных данных, а также его можно использовать для записи текстовых данных, как показано в следующем примере.

Path filePath = Path.of("demo.txt");String content = "hello world !!";//Write bytesFiles.write(filePath, content.getBytes());//Write linesList<String> lines = Arrays.asList("a", "b", "c");Files.write(filePath, lines, StandardCharsets.UTF_8);

3. Быстрая запись с помощью FileChannel и ByteBuffer

FileChannel может использоваться для чтения, записи, отображения и манипулирования файлом. Если мы записываем большие файлы, FileChannel может быть быстрее стандартного IO.

Файловые каналы безопасны для использования несколькими параллельными потоками.

Path fileName = Path.of("demo.txt");String content = "hello world !!";try(RandomAccessFile stream = new RandomAccessFile(filePath.toFile(),"rw");FileChannel channel = stream.getChannel();) {byte[] strBytes = content.getBytes();ByteBuffer buffer = ByteBuffer.allocate(strBytes.length);buffer.put(strBytes);buffer.flip();channel.write(buffer);}

4. Запись в текстовый файл с помощью BufferedWriter

BufferedWriter — наиболее традиционный и простой способ записи содержимого в файл. Он записывает текст в поток вывода символов, буферизуя символы, чтобы обеспечить эффективную запись отдельных символов, массивов и строк.

Если не требуется быстрый вывод, рекомендуется обернуть BufferedWriter вокруг любого Writer, операции write() которого могут быть затратными, например FileWriter и OutputStreamWriter, особенно при записи больших объемов данных.

Поскольку перед записью выполняется буферизация, это приводит к уменьшению количества операций ввода-вывода, что повышает производительность.

Path filePath = Path.of("demo.txt");String content = "hello world !!";try(BufferedWriter writer = new BufferedWriter(new FileWriter(filePath.toFile()))) {writer.write(content);}

5. Запись в файл с помощью FileWriter или PrintWriter

FileWriter — самый чистый способ записи файлов, синтаксис не требует пояснений, его легко читать и понимать. FileWriter записывает данные непосредственно в файл(производительность ниже), и его следует использовать только при небольшом количестве записей.

Поскольку FileWriter не обеспечивает буферизацию, это может привести к проблемам с производительностью при записи больших объемов данных.

Path filePath = Path.of("demo.txt");String content = "hello world !!";try(FileWriter fileWriter = new FileWriter(filePath.toFile())){fileWriter.write(content);}

Используйте PrintWriter для записи форматированного текста в файл. Этот класс реализует все методы печати, найденные в PrintStream, поэтому вы можете использовать все форматы, которые вы используете с операторами System.out.println().

Path filePath = Path.of("demo.txt");String content = "hello world !!";try(FileWriter fileWriter = new FileWriter(filePath.toFile());PrintWriter printWriter = new PrintWriter(fileWriter);){printWriter.print(content);printWriter.printf("Blog name is %s", "howtodoinjava.com");}

6. Запись в двоичный файл с помощью FileOutputStream

Используйте FileOutputStream для записи двоичных данных в файл. FileOutputStream предназначен для записи потоков необработанных байтов, таких как данные изображений. Для записи потоков символов рассмотрите возможность использования FileWriter.

Path filePath = Path.of("demo.txt");String content = "hello world !!";try(FileOutputStream outputStream = new FileOutputStream(filePath.toFile())){byte[] strToBytes = content.getBytes();outputStream.write(strToBytes);}

7. Запись в файл с помощью DataOutputStream

DataOutputStream позволяет приложению записывать примитивные типы данных Java в выходной поток переносимым способом. Затем приложение может использовать входной поток данных для обратного чтения данных.

Path filePath = Path.of("demo.txt");String content = "hello world !!";try(FileOutputStream outputStream= new FileOutputStream(filePath.toFile());DataOutputStream dataOutStream= new DataOutputStream(new BufferedOutputStream(outputStream));) {dataOutStream.writeUTF(content);dataOutStream.writeInt(10);dataOutStream.writeLong(100L);} 

7. Чистый код против производительности

При оценке производительности следует учитывать ряд факторов:

  • Удобство: Files.writeString() наиболее удобен для записи текстовых данных, в то время как Files.write() подходит для двоичных данных. Эти методы предоставляют простой в использовании API.
  • Буферизация: BufferedWriter и Files.write() обеспечивают буферизацию, которая может значительно повысить производительность записи, особенно при работе с большими объемами данных.
  • Двоичные данные против текстовых: Если вам нужно записывать двоичные данные, FileOutputStream — лучший выбор. Для текстовых данных решение зависит от уровня удобства и необходимости буферизации, как обсуждалось выше.

Для меньших файлов мы можем предпочесть читабельность, перевешивающую другие факторы, поскольку выигрыш в производительности будет незначительным. FileWriter и Files.writeString() должны быть предпочтительными вариантами в случае меньших файлов.

Для большого объема данных нам потребуется лучшая сырая производительность. В этом случае буферизованные методы, такие как BufferedWriter и Files.write(), могут предложить улучшенную эффективность.

В конечном итоге выбор метода должен зависеть от конкретных требований, таких как объем данных, простота и читаемость.

8. Резюме

  • Если мы попытаемся выполнить запись в несуществующий файл, файл будет сначала создан, и исключение не возникнет(за исключением использования метода Path).
  • Всегда закрывайте выходной поток после записи содержимого файла, чтобы освободить все ресурсы. Это также поможет не повредить файл.
  • PrintWriter используется для записи форматированного текста.
  • Используйте FileOutputStream для записи двоичных данных.
  • Используйте DataOutputStream для записи примитивных типов данных.
  • Используйте FileChannel для записи больших файлов. Это также предпочтительный способ записи файлов в Java 8.

Исходный код на Github

Прокрутить вверх