Перейти к основному содержимому

Руководство по классу Java FileReader

· 5 мин. чтения

1. Обзор

Как следует из названия, FileReader — это класс Java, упрощающий чтение содержимого файла .

В этом руководстве мы изучим базовую концепцию Reader и то, как мы можем использовать класс FileReader для выполнения операций чтения в потоке символов в Java.

2. Основы чтения

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

Это поднимает такие вопросы, как «Кто делает тяжелую работу за этим классом?»

Чтобы ответить на этот вопрос, мы должны понять концепцию и иерархию класса Reader в Java.

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

  • Чтение одного символа
  • Чтение массива символов
  • Отметить и сбросить заданную позицию в потоке символов
  • Пропустить позицию при чтении потока символов
  • Закрыть входной поток

Естественно, все реализации класса Reader должны реализовывать все абстрактные методы, а именно read() и close() . Более того, большинство реализаций также переопределяют другие унаследованные методы, чтобы обеспечить дополнительную функциональность или лучшую производительность.

2.1. Когда использовать FileReader

Теперь, когда у нас есть некоторое представление о Reader , мы готовы вернуться к классу FileReader .

FileReader наследует свою функциональность от InputStreamReader , который является реализацией Reader , предназначенной для чтения байтов из входного потока в виде символов.

Давайте посмотрим на эту иерархию в определениях классов:

public class InputStreamReader extends Reader {}

public class FileReader extends InputStreamReader {}

В общем, мы можем использовать InputStreamReader для чтения символов из любого источника ввода.

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

Мы можем использовать FileReader , когда хотим прочитать текст из файла, используя системный набор символов по умолчанию. Для любой другой расширенной функциональности было бы идеально использовать класс InputStreamReader напрямую.

3. Чтение текстового файла с помощью FileReader

Давайте рассмотрим упражнение по кодированию чтения символов из файла HelloWorld.txt с использованием экземпляра FileReader .

3.1. Создание FileReader

В качестве вспомогательного класса FileReader предлагает три перегруженных конструктора , которые можно использовать для инициализации модуля чтения, который может читать файл как источник ввода.

Давайте посмотрим на эти конструкторы:

public FileReader(String fileName) throws FileNotFoundException {
super(new FileInputStream(fileName));
}

public FileReader(File file) throws FileNotFoundException {
super(new FileInputStream(file));
}

public FileReader(FileDescriptor fd) {
super(new FileInputStream(fd));
}

В нашем случае мы знаем имя входного файла. Следовательно, мы можем использовать первый конструктор для инициализации считывателя:

FileReader fileReader = new FileReader(path);

3.2. Чтение одного символа

Далее создадим метод readAllCharactersOneByOne() для чтения символов из файла по одному:

public static String readAllCharactersOneByOne(Reader reader) throws IOException {
StringBuilder content = new StringBuilder();
int nextChar;
while ((nextChar = reader.read()) != -1) {
content.append((char) nextChar);
}
return String.valueOf(content);
}

Как видно из приведенного выше кода, мы использовали метод read() в цикле для чтения символов один за другим, пока он не вернет -1 , что означает, что больше нет символов для чтения.

Теперь давайте проверим наш код, убедившись, что текст, прочитанный из файла, соответствует ожидаемому тексту:

@Test
public void givenFileReader_whenReadAllCharacters_thenReturnsContent() throws IOException {
String expectedText = "Hello, World!";
File file = new File(FILE_PATH);
try (FileReader fileReader = new FileReader(file)) {
String content = FileReaderExample.readAllCharactersOneByOne(fileReader);
Assert.assertEquals(expectedText, content);
}
}

3.3. Чтение массива символов

Мы даже можем читать сразу несколько символов, используя унаследованный метод read(char cbuf[], int off, int len) :

public static String readMultipleCharacters(Reader reader, int length) throws IOException {
char[] buffer = new char[length];
int charactersRead = reader.read(buffer, 0, length);
if (charactersRead != -1) {
return new String(buffer, 0, charactersRead);
} else {
return "";
}
}

Есть небольшая разница в возвращаемом значении read() , когда речь идет о чтении нескольких символов в массиве. Возвращаемое значение здесь — либо количество прочитанных символов, либо -1 , если считыватель достиг конца входного потока.

Далее давайте проверим корректность нашего кода:

@Test
public void givenFileReader_whenReadMultipleCharacters_thenReturnsContent() throws IOException {
String expectedText = "Hello";
File file = new File(FILE_PATH);
try (FileReader fileReader = new FileReader(file)) {
String content = FileReaderExample.readMultipleCharacters(fileReader, 5);
Assert.assertEquals(expectedText, content);
}
}

4. Ограничения

Мы видели, что класс FileReader использует системную кодировку символов по умолчанию.

Итак, в ситуациях, когда нам нужно использовать пользовательские значения для набора символов, размера буфера или входного потока, мы должны использовать InputStreamReader .

Более того, все мы знаем, что циклы ввода-вывода обходятся дорого и могут привести к задержке в нашем приложении. Таким образом, в наших интересах свести к минимуму количество операций ввода-вывода, обернув BufferedReader вокруг нашего объекта FileReader :

BufferedReader in = new BufferedReader(fileReader);

5. Вывод

В этом руководстве мы узнали об основных концепциях Reader и о том, как FileReader упрощает выполнение операций чтения с текстовыми файлами на некоторых примерах.

Как всегда, полный исходный код руководства доступен на GitHub .