Перейти к содержанию

Файлы

Для работы с файлами в Node.js используется встроенный модуль fs, который выполняет все синхронные и асинхронные операции ввода/вывода применительно к файлам. Чтение и запись файла могут осуществляться одним из двумя способов:

  • с использованием Buffer;
  • через создание соответствующего потока.

Чтение файлов и директорий

Для чтения файла в асинхронном режиме используется метод Node.js readFile(), который принимает три параметра:

  • путь к файлу;
  • кодировка;
  • callback-функция, вызываемая после получения содержимого файла.
1
2
3
4
5
fs.readFile('files/data.txt', 'utf8', (err, data) => {
    if (err) throw err;

    console.log(data);
});

Callback-функции передается два аргумента: ошибка и полученные данные в строковом формате. Если операция прошла успешна, то в качестве ошибки передается null.

Если в readFile() не указать кодировку, то данные файла будут возвращены в формате Buffer.

Поскольку метод выполняется асинхронно, то не происходит блокировки главного процесса Node.js. Но в некоторых случаях может понадобиться синхронное чтение файла, для этого есть метод readFileSync(), но при этом выполнение главного процесса будет заблокировано до тех пор, пока полностью не будет загружено содержимое файла.

1
2
const content = fs.readFileSync('files/data.txt', 'utf8');
console.log(content);

Node.js readFileSync() возвращает результат чтения файла и принимает два параметра:

  • путь к файлу;
  • кодировку.

Обработка и перехват ошибок при использовании readFileSync() осуществляется с помощью конструкции try{...}catch(){...}.

1
2
3
4
5
6
7
8
9
try {
    const content = fs.readFileSync(
        'files/data.txt',
        'utf8'
    );
    console.log(content);
} catch (e) {
    console.log(e);
}

Чтобы инициировать ошибку, укажите неправильный путь к файлу.

Методы readFile() и readFileSync() для работы с файлами используют Buffer. Но есть и другой способ считать содержимое файла: создать поток с помощью Node.js fs.createReadStream(). Любой поток в Node.js является экземпляром класса EventEmitter, который позволяет обрабатывать возникающие в потоке события.

Параметры, принимаемые fs.createReadStream():

  • путь к файлу;
  • объект со следующими настройками:
    • encoding - кодировка (по умолчанию utf8);
    • mode - режим доступа (по умолчанию 0o666);
    • autoClose - если true, то при событиях error и finish поток закроется автоматически (по умолчанию true).
1
2
3
4
5
6
const stream = fs.createReadStream(
    'files/data.txt',
    'utf8'
);
stream.on('data', (data) => console.log(data));
stream.on('error', (err) => console.log(`Err: ${err}`));

Вместо объекта настроек можно передать строку, которая будет задавать кодировку.

Использование потока имеет ряд преимуществ перед Buffer:

  • Меньшее использование памяти за счет чтения содержимого по частям;
  • Для объемных файлов время между запросом и ответом существенно сокращается за счет того, что данные начинают поступать по частям, а не после полной загрузки;
  • Возможность перенаправить данные в другой поток с помощью метода pipe().

Для чтения директорий используются методы readdir() и readdirSync(), для асинхронного и синхронного режимов соответственно.

Node.js readdir() работает асинхронно и принимает три аргумента:

  • путь к директории;
  • кодировку;
  • callback-функцию, которая принимает аргументами ошибку и массив файлов директории (при успешном выполнении операции ошибка передается как null).
1
2
3
4
5
fs.readdir('files', 'utf8', (err, files) => {
    if (err) throw err;

    console.log(files);
});

Node.js readdirSync() работает синхронно, возвращает массив найденных файлов и принимает два параметра:

  • путь к директории;
  • кодировку.
1
2
3
4
5
6
try {
    const files = fs.readdirSync('files', 'utf8');
    console.log(files);
} catch (e) {
    console.log(e);
}

Создание и запись файлов и директорий

В Node.js файлы могут быть записаны также синхронно и асинхронно. Для асинхронной записи имеется метод writeFile(), принимающий следующие аргументы:

  • путь к файлу;
  • данные для записи;
  • параметры записи:
    • кодировка (по умолчанию utf8);
    • права доступа (по умолчанию 0o666);
  • callback-функция, которая вызывается по завершению операции и единственным аргументом принимает ошибку (в случае успешной записи передается null).
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
fs.writeFile(
    'files/data.txt',
    'File Content',
    'utf8',
    (err) => {
        if (err) throw err;

        console.log('Done');
    }
);

Если нет необходимости указывать параметры записи, то третьим параметром Node.js writeFile() можно сразу передать callback-функцию.

Для синхронной записи Node.js файла используйте writeFileSync(). Метод принимает все те же аргументы, что и writeFile() за исключением callback-функции. В качестве значения возвращает undefined.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
try {
    fs.writeFileSync(
        'files/data.txt',
        'File Content',
        'utf8'
    );
    console.log('Done');
} catch (e) {
    console.log(e);
}

Как и в случае с readFileSync() обработка ошибок происходит с помощью try{...}catch(){...}.

Методы writeFile() и writeFileSync() перезаписывают уже имеющуюся в файле информацию новыми данными. Если вам нужно внести новые данные без удаления старых, используйте методы appendFile() и appendFileSync(), которые имеют идентичные параметры.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
fs.appendFile(
    'files/data.txt',
    '\nFile Content 2',
    'utf8',
    (err) => {
        if (err) throw err;

        console.log('Done');
    }
);

Для записи файла через потока ввода имеется метод fs.createWriteStream(), который возвращает поток ввода и принимает два параметра:

  • путь к файлу;
  • объект со следующими настройками:
    • encoding - кодировка (по умолчанию utf8);
    • mode - режим доступа (по умолчанию 0o666);
    • autoClose - если true, то при событиях error и finish поток закроется автоматически (по умолчанию true).
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const stream = fs.createWriteStream(
    'files/data.txt',
    'utf8'
);

stream.on('error', (err) => console.log(`Err: ${err}`));
stream.on('finish', () => console.log('Done'));

stream.write('First line\n');
stream.write('Second line\n');
stream.end();

Чтобы создать директорию, используйте методы mkdir() и mkdirSync().

Node.js mkdir() работает асинхронно и принимает в качестве параметров:

  • путь к директории;
  • объект со следующими настройками:
    • recursive - если true, создает директорию и все ее родительские директории согласно указанному пути, если они еще не существуют (по умолчанию false, т. е. все родительские директории уже должны быть созданы, иначе будет сгенерирована ошибка);
    • mode - режим доступа, параметр не поддерживается на ОС Windows (по умолчанию 0o777);
    • callback-функцию, которая единственным аргументом принимает ошибку, при успешном создании директории передается null.

Вторым параметром можно сразу передать callback-функцию.

1
2
3
4
5
fs.mkdir('files/dir/subdir', { recursive: true }, (err) => {
    if (err) throw err;

    console.log('Created');
});

Node.js mkdirSync() создает директорию синхронно и возвращает undefined. Обработка ошибок осуществляется через try{...}catch(){...}. Метод mkdirSync() принимает те же параметры, что и mkdir(), за исключением callback-функции.

1
2
3
4
5
6
try {
    fs.mkdirSync('files/dir/subdir', { recursive: true });
    console.log('Done');
} catch (e) {
    console.log(e);
}

Удаление файлов и директорий

Чтобы удалить в Node.js файлы используйте методы unlink() и unlinkSync().

Метод unlink() асинхронный и принимает имя файла, который нужно удалить, и callback-функцию с ошибкой в качестве параметра (null, если удаление прошло успешно).

1
2
3
4
5
fs.unlink('files/data.txt', (err) => {
    if (err) throw err;

    console.log('Deleted');
});

Для синхронного удаления файла используйте unlinkSync(), которому единственным аргументом передается имя файла.

1
2
3
4
5
6
try {
    fs.unlinkSync('files/data.txt');
    console.log('Deleted');
} catch (e) {
    console.log(e);
}

Для удаления директорий имеются методы rmdir() и rmdirSync() соответственно. Они полностью идентичны unlink() и unlinkSync(), только вместо имени файла принимают имя директории.

Пример rmdir().

1
2
3
4
5
fs.rmdir('files/dir', (err) => {
    if (err) throw err;

    console.log('Deleted');
});

Пример rmdirSync().

1
2
3
4
5
6
try {
    fs.rmdirSync('files/dir');
    console.log('Deleted');
} catch (e) {
    console.log(e);
}

existsSync()

Проверка наличия в Node.js файла или директории происходит с помощью метода existsSync(), который принимает путь к файлу или директории и возвращает либо true, либо false. Как вы понимаете, Node.Js existsSync() работает в синхронном режиме.

1
2
3
4
5
6
try {
    const exists = fs.existsSync('files');
    console.log('Exists: ', exists);
} catch (e) {
    console.log(e);
}

Раньше был и Node.js exists(), но сейчас он уже официально устарел и не поддерживается.

Комментарии