Как прочитать текстовый файл?

При разработке программного обеспечения часто возникает необходимость читать и загружать различную информацию из файлов в программу. В языке Dart имеется несколько различных способов выполнять подобные действия. Рассмотрим возможности, которые предоставляет класс File для чтения информации:

  • readAsBytes, readAsBytesSync - Асинхронное или последовательное получение содержимого файла в виде массива байт
  • readAsLines, readAsLinesSync - Асинхронное или последовательное получение содержимого файла в виде массива строк
  • readAsString, readAsStringSync - Асинхронное или последовательное получение содержимого файла в виде одной строки

В данной статье рассмотрим последовательное и асинхронное чтение из файла с помощью методов readAsStringSync и readAsString, которые целиком читают содержимое файла в строковую переменную. Стоит отметить, что операции считывания всех данных сразу, при большом размере файла, может занять большой объем оперативной памяти, и привести к значительному снижению производительности, мы сейчас не будем останавливаться на этих проблемах.

Последовательное чтение текстовых файлов

Последовательная загрузка информации из файла в строковую переменную осуществляется с помощью метода File.readAsStringSync(), который возвращает содержание файла как одну строку, с учетом указанной в параметре Encoding encoding кодировки (по умолчанию, используется кодировка Encoding.UTF_8).

Для начала работы с операциями ввода-вывода, с помощью оператора import необходимо подключить библиотеку "dart:io":

import "dart:io";

После этого, мы можем объявить и инициализировать экземпляр класса File, указывающий на нужный нам документ. Сделать это проще всего с помощью конструктора File():

File myFile = new File("путь и имя файла");

Когда получен объект типа File можно непосредственно приступить к чтению текста:

String myFileContent = myFile.readAsStringSync();

Таким образом, простейшая программа на Dart для чтения информации из файла будет выглядеть следующим образом:

// подключаем стандартную библиотеку ввода-вывода
import "dart:io";

void main() {
  // создаем объект типа File
  File myFile = new File("путь и имя файла");

  // синхронно читаем все содержимое файла в переменную
  // с помощью метода readAsStringSync
  String myFileContent = myFile.readAsStringSync();
}

Но такой простой код, легко может привести к аварийному завершение программы в случае возникновения проблем с вводом-выводом, поэтому стоит добавить проверку на существование файла, которую можно осуществить с помощью метода File.existsSync(), и определить обработку исключительных ситуаций непосредственно при чтении с помощью блока try { ... } on FileIOException catch (e) { ... }

В итоге, получим следующую программу:

// подключаем стандартную библиотеку ввода-вывода
import "dart:io";

void main() {
  // создаем объект типа File, указывающий на нужный нам файл
  File fileText = new File('text.txt');

  // проверяем, существует ли требуемый файл
  if (fileText.existsSync()) {
    // в случае, если файл существует, пытаемся прочить его содержимое
    try {
      // синхронно прочитаем все содержимое файла в переменную
      // с помощью метода readAsStringSync
      String fileContent = fileText.readAsStringSync();

      // выведем полученное содержимое на экран
    print(fileContent);
    } on FileIOException catch (e) {
      // в исключительных ситуация оповестим пользователя
      print("возникли проблемы при чтении информации из файла!");
      print("ошибка - ${e.message}");
    }
  }
}

Асинхронное чтение текстовых файлов

Выше мы рассмотрели пример последовательной работы с файлом, когда управление в программу возвращается только после того, как полностью выполнится каждая операция ввода/вывода. Но бывают случаи, когда такое поведение "подвешивает" программу и она надолго перестает откликаться - например, если используется носитель с медленной скоростью чтения/записи, или производится обработка больших объёмов данных. Чтобы избежать таких ситуаций, в Dart можно использовать асинхронные операции ввода-вывода, которые сразу же возвращают управление, и программа продолжает выполняться дальше без задержек.

Асинхронная загрузка информации из файла в строковую переменную осуществляется с помощью метода File.readAsString(), который возвращает объект типа Future.

После вызова данного метода, управление не блокируется, а сразу же возвращается в основной поток, а обработка данных и исключительных ситуаций происходит позже, по мере готовности, с помощью методов объекта класса Future. В общем, этот класс предполагает обработку событий, которые произойдут в будущем. Когда событие успешно - вызывается метод Future.then(), если возникла исключительная ситуация вызывается Future.handleException().

Таким образом, мы можем адаптировать нашу программу для асинхронной обработки данных следующим образом:

  1. Заменим использование синхронных функций readAsStringSync и existsSync на асинхронные readAsString и exists
  2. Обработку результатов реализуем с помощью методов Future.then() и Future.handleException()

В итоге, получим следующую программу:

// подключаем стандартную библиотеку ввода-вывода
import "dart:io";

void main() {
  // создаем объект типа File, указывающий на нужный нам файл
  File fileText = new File('text.txt');

  // проверим, существует ли требуемый файл
  Future fileExistsFuture = fileText.exists();

  fileExistsFuture.then((bool exists) {
    if (exists) {
      // асинхронно запустим процесс чтения содержимого файла
      // с помощью метода readAsString
      Future fileContentFuture = fileText.readAsString();

      // определим функцию, отвечающую за обработку полученного
      // содержимого файла
      fileContentFuture.then((String fileContent) {
        // выведем полученное содержимое на экран
        print(fileContent);
      });

      // определим функцию, отвечающую за обработку исключительных
      // ситуаций
      fileContentFuture.handleException((FileIOException exception) {
        print("возникли проблемы при чтении информации из файла!");
        print("ошибка - ${exception.message}");
      });
    }
  });
}