Запись файлов в Node.js: writeFile, appendFile и потоки

Обзор
Node.js предоставляет встроенный модуль fs для работы с файловой системой. Основные способы записи файлов:
- writeFile — перезаписывает файл целиком (удобно для маленьких файлов).
- appendFile — добавляет данные в конец файла.
- createWriteStream — поддерживает последовательную (по частям) запись и подходит для больших объёмов.
Ниже — примеры, пояснения по флагам, рекомендации по использованию и чек‑лист для выбора подхода.
Использование writeFile
writeFile — самый простой метод записи файла в Node.
fs.writeFile(filename, data, callback)Пример создания текстового файла с помощью writeFile():
const fs = require("fs")
fs.writeFile("test.txt", "New content", err => {
if (err) {
console.log(err)
}
});Поддерживается async/await, если использовать промисы:
const fs = require("fs").promises
async function writeToFile() {
try {
await fs.writeFile("test.txt", "New cont")
} catch (err) {
console.log(err);
}
}
writeToFile()По умолчанию writeFile заменяет содержимое файла. Чтобы изменить поведение, применяют флаги:
- r+ — открыть для чтения и записи.
- w+ — открыть для чтения и записи с начала файла.
- a — открывает файл для записи в конец.
- a+ — открыть для чтения и записи в конец.
Пример с флагом a+:
const fs = require("fs")
fs.writeFile("test.txt", "Newer content", { flag: "a+" }, err => {
if (err) {
console.log(err)
}
});Важно: модуль fs также предоставляет синхронную версию writeFile — writeFileSync. Синхронные вызовы блокируют поток выполнения и обычно нежелательны в серверных приложениях.
const fs = require("fs")
// синхронная запись (без callback)
fs.writeFileSync("test.txt", "Newer content", { flag: "a+" });Важно: используйте writeFileSync только в скриптах или при инициализации, когда блокировка потока не является проблемой.
Использование createWriteStream
Недостаток writeFile — весь контент должен быть в памяти одновременно. Для больших файлов это не масштабируется. createWriteStream поддерживает последовательную запись: вы записываете данные кусками.
fs.createWriteStream(path, options)Пример записи через поток:
const fs = require("fs")
// create a writable stream
let writeableStream = fs.createWriteStream("test.txt")
// Write to the file using the writable stream
writeableStream.write("New content");Пример с pipe: весь ввод из терминала будет записан в test.txt пока открыт терминал.
const fs = require("fs")
let writableStream = fs.createWriteStream("test.txt");
process.stdin.pipe(writableStream);Если запускать такую программу из командной строки, можно выйти с помощью Ctrl + D или Ctrl + C.
Копирование файла через чтение и запись кусками (ручной подход):
const fs = require("fs")
let readableStream = fs.createReadStream("test.txt");
let writableStream = fs.createWriteStream("test2.txt");
readableStream.on("data", function(chunk) {
writableStream.write(chunk);
});Более простой и надёжный подход — использовать pipe, который учитывает обратное давление (backpressure):
const fs = require("fs")
const rs = fs.createReadStream("largefile.bin")
const ws = fs.createWriteStream("copy.bin")
rs.pipe(ws)События, на которые стоит подписываться при работе с writable stream:
- finish — запись завершена, если был вызван end().
- error — произошла ошибка записи.
Пример с обработкой ошибок и завершения:
writeableStream.on("finish", () => console.log("Запись завершена"));
writeableStream.on("error", err => console.error("Ошибка записи:", err));
writeableStream.end();Использование appendFile
appendFile добавляет контент в конец файла — удобно для логов или добавочных записей.
const fs = require("fs")
fs.appendFile("test.txt", "added content", err => {
if (err) {
console.error(err);
}
});С async/await через промисы:
const fs = require("fs").promises
async function appendToFile() {
try {
await fs.appendFile("test.txt", "added content")
} catch (err) {
console.log(err);
}
}
appendToFile()Есть и синхронный вариант:
fs.appendFileSync("test.txt", "added content");Когда какой метод выбирать
Ментальная модель: думайте о размере, частоте и требовании к последовательности записи.
- Небольшой файл (< несколько мегабайт) и единичная операция → writeFile.
- Частые добавления (логи) → appendFile или write stream с режимом append.
- Большой поток данных, копирование файлов, трансляция → createWriteStream.
flowchart TD
A[Небольшой файл или разовая запись] -->|Да| B[use writeFile]
A -->|Нет| C[Большой файл или поток данных]
C --> D{Копирование или передача потока?}
D -->|Да| E[createReadStream → pipe → createWriteStream]
D -->|Нет| F[createWriteStream]Чек-лист разработчика
- Выберите writeFile для простых операций и когда память не критична.
- Для логирования используйте appendFile или writeStream с флагом “a”.
- Для больших файлов используйте потоки и pipe; подписывайтесь на error и finish.
- Не используйте синхронные методы в серверном коде.
- Тестируйте поведение при возникновении ошибок (права доступа, недостаточно места).
Критерии приёмки
- Файл создаётся/обновляется без ошибок в обычных условиях.
- Для потоковой записи не наблюдается утечек памяти при больших объёмах.
- Ошибки записи корректно логируются и очевидны для оператора.
- При копировании файл на приёме имеет ту же длину/контент, что и оригинал.
Примеры, когда это не годится
- writeFile не подходит для многогигабайтных файлов: потребует много памяти.
- appendFile не гарантирует атомарность нескольких операций без дополнительной синхронизации.
- createWriteStream требует обработки ошибок и может потребовать управления обратным давлением при сложных сценариях.
Небольшая шпаргалка (cheat sheet)
| Сценарий | Метод |
|---|---|
| Однократная запись небольшого файла | writeFile / writeFileSync |
| Добавление строки в лог | appendFile |
| Копирование большого файла | createReadStream.pipe(createWriteStream) |
| Постепенная генерация данных | createWriteStream |
1‑строчный глоссарий
- fs — модуль файловой системы Node.js.
- stream — последовательный поток данных (readable/writable).
- backpressure — механизм управления скоростью между читающим и пишущим потоками.
Итог
Выбор между writeFile, appendFile и createWriteStream зависит от объёма данных и требований к последовательности записи. Для небольших и простых задач используйте writeFile. Для добавлений — appendFile. Для больших объёмов и потоковой обработки — createWriteStream и pipe.
Короткий чек‑лист повторно: проверьте размер данных, частоту записи, обработку ошибок и тесты на производительность.
Похожие материалы
RDP: полный гид по настройке и безопасности
Android как клавиатура и трекпад для Windows
Советы и приёмы для работы с PDF
Calibration в Lightroom Classic: как и когда использовать
Отключить Siri Suggestions на iPhone