Автор оригинала: Scott Robinson.
Вступление
В этой статье мы погрузимся в Чтение и запись файлов на Java .
При программировании, независимо от того, создаете ли вы мобильное приложение, веб-приложение или просто пишете сценарии, вам часто приходится читать или записывать данные в файл. Эти данные могут быть данными кэша, данными, которые вы получили для набора данных, изображения или практически всем, что вы можете придумать.
В этом уроке мы покажем наиболее распространенные способы чтения и записи файлов на Java.
Java предоставляет несколько API (также известных как Java I/O ) для чтения и записи файлов с момента ее первых выпусков. В последующих выпусках ввод-вывод Java был улучшен, упрощен и расширен для поддержки новых функций.
Прежде чем мы перейдем к некоторым реальным примерам, это поможет понять доступные вам классы, которые будут обрабатывать чтение и запись данных в файлы. В следующих разделах мы дадим краткий обзор классов ввода-вывода Java и объясним, что они делают, затем мы рассмотрим потоки Java NIO и, наконец, покажем некоторые примеры чтения и записи данных в файлы.
Потоки ввода-вывода
Существует два типа потоков, которые вы можете использовать для взаимодействия с файлами:
- Потоки символов
- Потоки байтов
Для каждого из вышеперечисленных типов потоков существует несколько вспомогательных классов, поставляемых с Java, которые мы кратко рассмотрим ниже.
Потоки символов
Потоки символов используются для чтения или записи типа данных символов. Давайте рассмотрим наиболее часто используемые классы. Все эти классы определены в разделе java.io
посылка.
Вот некоторые классы, которые вы должны знать, которые можно использовать для чтения символьных данных:
- Reader : Абстрактный класс для чтения потока символов.
- InputStreamReader : Класс, используемый для чтения потока байтов и преобразования в поток символов.
- Средство чтения файлов : Класс для чтения символов из файла.
- BufferedReader : Это оболочка над классом
Reader
, которая поддерживает возможности буферизации. Во многих случаях это наиболее предпочтительный класс для чтения данных, поскольку из файла можно прочитать больше данных за один вызовread ()
, что уменьшает количество фактических операций ввода-вывода с файловой системой.
И вот некоторые классы, которые вы можете использовать для записи символьных данных в файл:
- Writer : Это абстрактный класс для записи потоков символов.
- OutputStreamWriter : Этот класс используется для записи потоков символов, а также для преобразования их в потоки байтов.
- Пишущая машинка : Класс для фактической записи символов в файл.
- BufferedWriter : Это оболочка над классом
Writer
, которая также поддерживает возможности буферизации. Это наиболее предпочтительный класс для записи данных в файл, так как в файл может быть записано больше данных за один вызовwrite ()
. И , как иBufferedReader
, это уменьшает общее количество операций ввода-вывода с файловой системой.
Потоки байтов
Потоки байтов используются для чтения или записи байтовых данных с файлами. Это отличается от того, как они обрабатывали данные раньше. Здесь вы работаете с необработанными байтами, которые могут быть символами, данными изображений, данными в юникоде (для представления символа требуется 2 байта) и т. Д.
В этом разделе мы рассмотрим наиболее часто используемые классы. Все эти классы определены в разделе java.io
посылка.
Вот классы, используемые для чтения байтовых данных:
- InputStream : Абстрактный класс для чтения потоков байтов.
- FileInputStream : Класс для простого считывания байтов из файла.
- BufferedInputStream : Это оболочка над
InputStream
, которая поддерживает возможности буферизации. Как мы видели в потоках символов, это более эффективный метод, чемFileInputStream
.
А вот классы, используемые для записи байтовых данных:
- OutputStream : Абстрактный класс для записи байтовых потоков.
- FileOutputStream : Класс для записи необработанных байтов в файл.
- ByteOutputStream : Этот класс является оболочкой над
OutputStream
для поддержки возможностей буферизации. И опять же, как мы видели в потоках символов, это более эффективный метод, чемFileOutputStream
благодаря буферизации.
Потоки Java NIO
Java NIO -это неблокирующий API ввода-вывода, который был представлен еще в Java 4 и может быть найден в пакете/| java.nio . С точки зрения производительности это большое улучшение API для операций ввода-вывода.
Буферы, селекторы и каналы являются тремя основными компонентами Java NIO, хотя в этой статье мы сосредоточимся исключительно на использовании классов NIO для взаимодействия с файлами, а не обязательно на концепциях, лежащих в основе API.
Поскольку этот учебник посвящен чтению и записи файлов, в этом коротком разделе мы обсудим только связанные классы:
- Путь : Это иерархическая структура фактического расположения файла и обычно используется для поиска файла, с которым вы хотите взаимодействовать.
- Пути : Это класс, который предоставляет несколько служебных методов для создания
Пути
из заданного URI строки. - Файлы : Это еще один служебный класс, который имеет несколько методов для чтения и записи файлов, не блокируя выполнение в потоках.
Используя эти несколько классов, вы можете легко взаимодействовать с файлами более эффективным способом.
Разница между вводом-выводом Java и NIO
Основное различие между этими двумя пакетами заключается в том, что методы read()
и write()
блокируют вызовы области ввода-вывода Java. Под этим мы подразумеваем, что поток, вызывающий один из этих методов, будет заблокирован до тех пор, пока данные не будут прочитаны или записаны в файл.
С другой стороны, в случае NIO методы не являются блокирующими. Это означает, что вызывающие потоки могут выполнять другие задачи (например, чтение/запись данных из другого источника или обновление пользовательского интерфейса), в то время как методы чтение
или запись
ожидают завершения своей операции. Это может привести к значительному повышению производительности, если вы имеете дело с большим количеством запросов ввода-вывода или большим количеством данных.
Примеры чтения и записи текстовых файлов
В предыдущих разделах мы обсуждали различные API, предоставляемые Java, и теперь пришло время использовать эти классы API в некотором коде.
Приведенный ниже пример кода обрабатывает чтение и запись текстовых файлов с использованием различных классов, которые мы подробно описали выше. Чтобы упростить вещи и обеспечить лучшее сравнение используемых фактических методов, входные и выходные данные будут оставаться одинаковыми между примерами.
Git Essentials
Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!
Примечание : Чтобы избежать путаницы в пути к файлу, пример кода будет считываться и записываться из файла в домашнем каталоге пользователя. Домашний каталог пользователя можно найти с помощью System.getProperty("user.home");
, который мы используем в наших примерах.
Чтение и запись с помощью программы чтения файлов и пишущей машинки
Давайте начнем с использования классов FileReader
и Пишущая машинка
:
String directory = System.getProperty("user.home"); String fileName = "sample.txt"; String absolutePath = directory + File.separator + fileName; // Write the content in file try(FileWriter fileWriter = new FileWriter(absolutePath)) { String fileContent = "This is a sample text."; fileWriter.write(fileContent); fileWriter.close(); } catch (IOException e) { // Cxception handling } // Read the content from file try(FileReader fileReader = new FileReader(absolutePath)) { int ch = fileReader.read(); while(ch != -1) { System.out.print((char)ch); fileReader.close(); } } catch (FileNotFoundException e) { // Exception handling } catch (IOException e) { // Exception handling }
Оба класса принимают строку, представляющую путь к файлу в их конструкторах. Вы также можете передать Файл
объект, а также Файловый дескриптор
.
Метод write()
записывает допустимую последовательность символов – либо Строку
, либо символ[]
. Кроме того, он может записать один символ
, представленный как int
.
Метод read()
считывает и возвращает символ за символом, позволяя нам, например, использовать считанные данные в цикле while
.
Не забудьте закрыть оба этих класса после использования!
Чтение и запись с помощью BufferedReader и BufferedWriter
Использование BufferedReader
и BufferedWriter
классов:
String directory = System.getProperty("user.home"); String fileName = "sample.txt"; String absolutePath = directory + File.separator + fileName; // Write the content in file try(BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(absolutePath))) { String fileContent = "This is a sample text."; bufferedWriter.write(fileContent); } catch (IOException e) { // Exception handling } // Read the content from file try(BufferedReader bufferedReader = new BufferedReader(new FileReader(absolutePath))) { String line = bufferedReader.readLine(); while(line != null) { System.out.println(line); line = bufferedReader.readLine(); } } catch (FileNotFoundException e) { // Exception handling } catch (IOException e) { // Exception handling }
Чтение и запись с помощью FileInputStream и FileOutputStream
Использование FileInputStream
и FileOutputStream
классов:
String directory = System.getProperty("user.home"); String fileName = "sample.txt"; String absolutePath = directory + File.separator + fileName; // write the content in file try(FileOutputStream fileOutputStream = new FileOutputStream(absolutePath)) { String fileContent = "This is a sample text."; fileOutputStream.write(fileContent.getBytes()); } catch (FileNotFoundException e) { // exception handling } catch (IOException e) { // exception handling } // reading the content of file try(FileInputStream fileInputStream = new FileInputStream(absolutePath)) { int ch = fileInputStream.read(); while(ch != -1) { System.out.print((char)ch); ch = fileInputStream.read(); } } catch (FileNotFoundException e) { // exception handling } catch (IOException e) { // exception handling }
Чтение и запись с помощью BufferedInputStream и BufferedOutputStream
Использование BufferedInputStream
и BufferedOutputStream
классов:
String directory = System.getProperty("user.home"); String fileName = "sample.txt"; String absolutePath = directory + File.separator + fileName; // write the content in file try(BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(absolutePath))) { String fileContent = "This is a sample text."; bufferedOutputStream.write(fileContent.getBytes()); } catch (IOException e) { // exception handling } // read the content from file try(BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(absolutePath))) { int ch = bufferedInputStream.read(); while(ch != -1) { System.out.print((char)ch); ch = bufferedInputStream.read(); } } catch (FileNotFoundException e) { // exception handling } catch (IOException e) { // exception handling }
Чтение и запись с помощью классов Java.nio
Использование классов java.nio
:
String directory = System.getProperty("user.home"); String fileName = "sample.txt"; String content = "This is a sample text."; Path path = Paths.get(directory, fileName); try { Files.write(path, content.getBytes(), StandardOpenOption.CREATE); } catch (IOException e) { // exception handling } try { Listlist = Files.readAllLines(path); list.forEach(line -> System.out.println(line)); } catch (IOException e) { // exception handling }
Другой способ извлечения содержимого через класс Files
, что более важно, если вы не читаете текстовые данные, – это использовать метод ReadAllBytes
для чтения данных в массив байтов:
try { byte[] data = Files.readAllBytes(path); System.out.println(new String(data)); } catch (IOException e) { // exception handling }
В случае , если вы заинтересованы в использовании потоков с java.nio
, вы также можете использовать приведенные ниже методы, предоставляемые классом Files
, которые работают так же, как потоки, которые мы рассмотрели ранее в статье:
Files.newBufferedReader(path) Files.newBufferedWriter(path, options) Files.newInputStream(path, options) Files.newOutputStream(path, options)
Вывод
В этой статье мы рассмотрели наиболее распространенные способы чтения и записи данных в файл с использованием как пакета ввода-вывода Java, так и более нового пакета Java NIO. Всякий раз, когда это возможно, мы рекомендуем использовать классы Java NIO для файловых операций из-за его неблокирующего API, и, кроме того, код немного более удобен для обслуживания и чтения.