Вступление
В этой статье мы углубимся в чтение и запись файлов на Java .
При программировании, независимо от того, создаете ли вы мобильное приложение, веб-приложение или просто пишете сценарии, вам часто нужно читать или записывать данные в файл. Эти данные могут быть данными кеша, данными, полученными вами для набора данных, изображением или чем-либо еще, что вы можете придумать.
В этом руководстве мы покажем наиболее распространенные способы чтения и записи файлов в Java.
Java предоставляет несколько API (также известных как Java I / O ) для чтения и записи файлов с момента его первых выпусков. В последующих выпусках ввод-вывод Java был улучшен, упрощен и расширен для поддержки новых функций.
Прежде чем мы перейдем к некоторым реальным примерам, это поможет понять доступные вам классы, которые будут обрабатывать чтение и запись данных в файлы. В следующих разделах мы дадим краткий обзор классов ввода-вывода Java и объясним, что они делают, затем мы рассмотрим потоки Java NIO и, наконец, покажем несколько примеров чтения и записи данных в файлы.
Потоки ввода / вывода
Есть два типа потоков, которые вы можете использовать для взаимодействия с файлами:
- Потоки персонажей
- Байтовые потоки
Для каждого из вышеперечисленных типов потоков есть несколько поддерживающих классов, поставляемых с Java, которые мы кратко рассмотрим ниже.
Потоки персонажей
Потоки символов используются для чтения или записи типа данных символов.
Давайте посмотрим на наиболее часто используемые классы. Все эти классы
определены в пакете java.io
Вот несколько классов, которые вы должны знать, которые можно использовать для чтения символьных данных:
-
- Читатель
- абстрактный класс для чтения потока символов.
-
- InputStreamReader
- класс, используемый для чтения байтового потока и преобразования в символьный поток.
-
- FileReader
- класс для чтения символов из файла.
-
- BufferedReader
- это оболочка над
Reader
, поддерживающая возможности буферизации. Во многих случаях это наиболее предпочтительный класс для чтения данных, поскольку за одинread()
из файла может быть прочитано больше данных, что сокращает количество фактических операций ввода-вывода с файловой системой.
А вот несколько классов, которые вы можете использовать для записи символьных данных в файл:
-
- Writer
- это абстрактный класс для записи символьных потоков.
-
- OutputStreamWriter
- этот класс используется для записи символьных потоков, а также их преобразования в байтовые потоки.
-
- FileWriter
- класс для записи символов в файл.
-
- BufferedWriter
- это оболочка над
Writer
, который также поддерживает возможности буферизации. Это наиболее предпочтительный класс для записи данных в файл, поскольку за один вызовwrite()
Как иBufferedReader
, это уменьшает общее количество операций ввода-вывода с файловой системой.
Байтовые потоки
Потоки байтов используются для чтения или записи байтовых данных с файлами. Это отличается от предыдущего способом обработки данных. Здесь вы работаете с необработанными байтами, которые могут быть символами, данными изображения, данными Unicode (для представления символа требуется 2 байта) и т. Д.
В этом разделе мы рассмотрим наиболее часто используемые классы. Все эти
классы определены в пакете java.io
Вот классы, используемые для чтения байтовых данных:
-
- InputStream
- абстрактный класс для чтения байтовых потоков.
-
- FileInputStream
- класс для простого чтения байтов из файла.
-
- BufferedInputStream
- это оболочка над
InputStream
которая поддерживает возможности буферизации. Как мы видели в потоках символов, это более эффективный метод, чемFileInputStream
.
А вот классы, используемые для записи байтовых данных:
-
- OutputStream
- абстрактный класс для записи байтовых потоков.
-
- FileOutputStream
- класс для записи необработанных байтов в файл.
-
- ByteOutputStream
- этот класс является оболочкой над
OutputStream
для поддержки возможностей буферизации. И снова, как мы видели в потоках символов, это более эффективный метод, чемFileOutputStream
благодаря буферизации.
Потоки Java NIO
- это неблокирующий API ввода-вывода, который был представлен еще в Java
4 и может быть найден в пакете
java.nio
С точки зрения производительности это большое улучшение API для операций ввода-вывода.
Буферы, селекторы и каналы - три основных компонента Java NIO, хотя в этой статье мы сосредоточимся строго на использовании классов NIO для взаимодействия с файлами, а не обязательно на концепциях, лежащих в основе API.
Поскольку это руководство посвящено чтению и записи файлов, в этом коротком разделе мы обсудим только связанные классы:
-
- Путь
- это иерархическая структура фактического расположения файла, которая обычно используется для поиска файла, с которым вы хотите взаимодействовать.
-
- Пути
- это класс, который предоставляет несколько служебных методов для
создания
Path
из заданного строкового URI.
-
- Файлы
- это еще один служебный класс, который имеет несколько методов для чтения и записи файлов без блокировки выполнения в потоках.
Используя эти несколько классов, вы можете легко и эффективно взаимодействовать с файлами.
Разница между вводом-выводом Java и NIO
Основное различие между этими двумя пакетами заключается в том, что
read()
и write()
Java IO являются блокирующими вызовами. Под этим мы
подразумеваем, что поток, вызывающий один из этих методов, будет
заблокирован до тех пор, пока данные не будут прочитаны или записаны в
файл.
С другой стороны, в случае NIO методы неблокирующие. Это означает, что
вызывающие потоки могут выполнять другие задачи (например, чтение /
запись данных из другого источника или обновление пользовательского
интерфейса), в то время write
read
или записи ожидают завершения
своей операции. Это может привести к значительному увеличению
производительности, если вы имеете дело с большим количеством запросов
ввода-вывода или большого количества данных.
Примеры чтения и записи текстовых файлов
В предыдущих разделах мы обсудили различные API, предоставляемые Java, и теперь пора использовать эти классы API в некотором коде.
В приведенном ниже примере кода выполняется чтение и запись текстовых файлов с использованием различных классов, которые мы подробно описали выше. Чтобы упростить ситуацию и обеспечить лучшее сравнение фактически используемых методов, входные и выходные данные в примерах останутся неизменными.
Примечание . Чтобы избежать путаницы в пути к файлу, пример кода
будет читать и писать из файла в домашнем каталоге пользователя.
Домашний каталог пользователя можно найти с помощью
System.getProperty("user.home");
, что мы и используем в наших
примерах.
Чтение и запись с помощью FileReader и FileWriter
Начнем с использования классов FileReader
и FileWriter
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
}
Оба класса принимают String, представляющую путь к файлу в своих
конструкторах. Вы также можете передать File
а также FileDescriptor
.
Метод write()
записывает допустимую последовательность символов - либо
String
, либо char[]
. Кроме того, он может записать один char
представленный как 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<String> 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, и, кроме того, код более удобен в обслуживании и читается.