Рубрики
Без рубрики

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

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

Автор оригинала: baeldung.

1. Обзор

Как следует из названия, File Reader – это класс Java, который позволяет легко читать содержимое файла .

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

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

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

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

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

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

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

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

2.1. Когда следует использовать средство чтения файлов

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

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

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

public class InputStreamReader extends Reader {}

public class FileReader extends InputStreamReader {}

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

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

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

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

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

3.1. Создание программы чтения файлов

В качестве удобного класса 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 .