Асинхронная работа с fs через коллбэки в NodeJS

Давайте теперь рассмотрим асинхронную работу с файловой системой. Как правило, в NodeJS все методы модуля fs существуют в двух вариантах: в синхронном и асинхронном.

Например, для синхронного чтения файла используется метод readFileSync, а для асинхронного - readFile. Аналогично для записи файла существует пара writeFileSync и writeFile.

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

Метод readFile первым параметром принимает имя или путь к файлу, вторым параметром - кодировку, а третьим - коллбэк, который выполнится после чтения файла.

В коллбэк следует передавать два параметра. В первый параметр попадет объект с ошибкой, если она произойдет, а во второй - текст прочитанного файла.

Давайте для примера прочитаем текст какого-нибудь файла:

javascriptfs.readFile('readme.txt', 'utf8', function(err, data) {
  console.log(data);
});
Задание 1

Дан файл с числом. Прочитайте этот файл и выведите в консоль квадрат этого числа.

Проверка асинхронности

Можно убедится в том, что чтение файла происходит асинхронно. Для этого выведем что-нибудь в консоль после работы с методом readFile:

javascriptfs.readFile('readme.txt', 'utf8', function(err, data) {
  console.log(data);
});

console.log('!!!');

Как вы уже знаете, коллбэк выполнится, когда файл будет прочитан. А пока файл читается, код скрипта будет выполнятся дальше. Это значит, что в консоли сначала появится результат второго console.log, а потом первого.

Задание 2

Проверьте, что код после метода readFile будет выполнен раньше, чем будет прочитан файл.

Обработка исключительных ситуаций

Так как наш код асинхронный, то исключительные ситуации нельзя поймать через try-catch. Для обработки исключений в коллбэке предназначен первый параметр. Этот параметр будет содержать null, если исключения не случилось, или объект с ошибкой, если исключение произошло.

Давайте допишем код коллбэка так, чтобы он обрабатывал исключительные ситуации:

javascriptfs.readFile('readme.txt', 'utf8', function(err, data) {
  if (!err) {
    console.log(data);
  } else {
    console.log('ошибка', err);
  }
});
Задание 3

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

Асинхронная запись файла

Асинхронная запись текста в файл выполняется аналогично:

javascriptfs.writeFile('readme.txt', 'text', function(err) {
  if (err) {
    console.log('ошибка');
  }
});
Задание 4

С помощью цикла создайте 10 файлов, содержащих целые числа от 1 до 10.

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

Пусть у нас есть два файла с числами. Давайте найдем произведение этих чисел. Очевидно, что для этого нам нужно прочитать оба этих файла.

Но, так как код асинхронный, нам нужно читать второй файл в коллбэке первого:

javascriptfs.readFile('readme1.txt', 'utf8', function(err, data1) {
  if (!err) {
    fs.readFile('readme2.txt', 'utf8', function(err, data2) {
      if (!err) {
        console.log(data1 * data2);
      } else {
        console.log('ошибка чтения файла readme2');
      }
    });
  } else {
    console.log('ошибка чтения файла readme1');
  }
});
Задание 5

Даны три файла с числами. Выведите в консоль сумму этих чисел.

Задание 6

Даны пять файлов с числами. Выведите в консоль сумму этих чисел.

Асинхронное чтение и запись файла

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

javascriptfs.readFile('readme.txt', 'utf8', function(err, data) {
  if (!err) {
    fs.writeFile('readme.txt', data + '!', function(err) {
      if (err) {
        console.log('ошибка записи файла');
      }
    });
  } else {
    console.log('ошибка чтения файла');
  }
});
Задание 7

Дан файл с числом. Запишите в этот файл квадрат этого числа.

Задание 8

Даны три файла с числами. Запишите в новый файл сумму этих чисел.

Стрелочные функции

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

Давайте переделаем предыдущий код на стрелочные функции:

javascriptfs.readFile('readme.txt', 'utf8', (err, data) => {
  if (!err) {
    fs.writeFile('readme.txt', data + '!', err => {
      if (err) {
        console.log('ошибка записи файла');
      }
    });
  } else {
    console.log('ошибка чтения файла');
  }
});
Задание 9

Дан код:

javascriptfs.readFile('readme1.txt', 'utf8', function(err, data1) {
  if (!err) {
    fs.readFile('readme2.txt', 'utf8', function(err, data2) {
      if (!err) {
        fs.writeFile('readme.txt', data1 + data2, function(err) {
          if (err) {
            console.log('ошибка записи файла');
          }
        });
      } else {
        console.log('ошибка чтения файла readme2');
      }
    });
  } else {
    console.log('ошибка чтения файла readme1');
  }
});

Перепишите его через стрелочные функции.