Вступление
В этой статье мы углубимся в чтение и запись файлов на 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, и, кроме того, код более удобен в обслуживании и читается.