Автор оригинала: 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 {
List list = 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, и, кроме того, код немного более удобен для обслуживания и чтения.