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

Краткое описание методов
- writeFile — записывает данные в файл; по умолчанию заменяет содержимое.
- appendFile — добавляет данные в конец файла.
- createWriteStream — создаёт записываемый поток; подходит для больших файлов и последовательной записи.
Важно: термин “поток” (stream) — это последовательность данных, которую можно читать или записывать частями, не загружая весь файл в память.
Использование writeFile()
writeFile() — самый простой способ записать файл в Node.js.
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);
}
});Существует также синхронная версия writeFileSync:
const fs = require("fs");
fs.writeFileSync("test.txt", "Newer content", { flag: "a+" });(Для синхронных вызовов исключения следует обрабатывать через try/catch.)
Использование createWriteStream()
Если файл большой или вы получаете данные по частям, потоковая запись предпочтительнее: она не требует загрузки всего содержимого в память.
Создание записываемого потока:
const fs = require("fs");
// create a writable stream
let writableStream = fs.createWriteStream("test.txt");
// Запись в файл через поток
writableStream.write("New content");
// Не забывайте закрыть поток, когда закончите
writableStream.end();Пример использования pipe: перенаправление ввода терминала в файл:
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);
});
readableStream.on("end", function() {
writableStream.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();Синхронная версия:
const fs = require("fs");
fs.appendFileSync("test.txt", "added content");Когда выбирать тот или иной метод
- Маленькие файлы (< несколько мегабайт) и простые операции: writeFile / appendFile. Простая реализация, понятная обработка ошибок.
- Большие файлы, потоковый ввод/вывод, конвейеры (pipeline): createWriteStream. Экономия памяти и возможность контроля потока данных.
- Нужна атомарная запись или блокировка доступа: рассматривайте дополнительные модули/библиотеки для атомарных операций (fs.rename/временные файлы).
Important: для серверных приложений избегайте частых синхронных вызовов в основном потоке — они блокируют event loop.
Сравнительная таблица
| Метод | Когда подходит | Плюсы | Минусы |
|---|---|---|---|
| writeFile / writeFileSync | Малые файлы и одноразовые записи | Простота | Потребляет память для полного содержимого; sync блокирует loop |
| appendFile / appendFileSync | Добавление в конец файла | Простота добавления | То же ограничение по памяти в async варианте при больших буферах |
| createWriteStream | Большие файлы, потоковая запись | Память экономится; поддержка backpressure | Теперь нужно управлять событиями/закрытием потока |
Модель принятия решения (Mermaid)
flowchart TD
A[Нужно записать данные?] --> B{Данные маленькие?}
B -- Да --> C[writeFile или appendFile]
B -- Нет --> D{Данные приходят частями?}
D -- Да --> E[createWriteStream]
D -- Нет --> F[Разбить на чанки или использовать поток]
C --> G[Проверьте флаги и обработку ошибок]
E --> G
F --> GРоль‑ориентированный чеклист
Для разработчика:
- Выбрать метод по размеру данных и частоте записей.
- Обработать ошибки (callback/try-catch/параметры событий).
- Закрыть поток (writable.end()).
Для DevOps:
- Мониторить использование диска и I/O.
- Настроить логирование и ротацию файлов при необходимости.
Для архитектора:
- Принять решение об атомарности и согласованности данных.
- Оценить потребности в резервировании и бэкапах.
Памятка: быстрые примеры
Записать JSON файл асинхронно:
const fs = require("fs").promises;
async function saveJson(file, obj) {
await fs.writeFile(file, JSON.stringify(obj, null, 2));
}Потоковое сохранение больших данных:
const fs = require("fs");
const stream = fs.createWriteStream("bigfile.bin");
// Получаем чанки (например, от сети) и вызываем stream.write(chunk);
// в конце stream.end();Копирование с использованием pipe (рекомендуемый паттерн):
const fs = require("fs");
fs.createReadStream("source.txt").pipe(fs.createWriteStream("dest.txt"));Контрпримеры и когда методы не подходят
- writeFile не подходит, если файл > доступной оперативной памяти.
- Синхронные версии неприемлемы в высоконагруженных серверах.
- Для файлов, требующих атомарной замены, простая запись в существующий файл может привести к непоследовательности при сбоях — используйте временные файлы + переименование.
Критерии приёмки
- Файл создаётся/обновляется без ошибок в типичных сценариях.
- Для потоков: данные полностью попадают в файл и поток корректно закрывается.
- Для append: данные добавляются в конец, порядок сохраняется.
- Нагрузочные тесты показывают приемлемое потребление памяти и времени.
Однострочный глоссарий
- stream — последовательность данных, читаемая/записываемая частями; backpressure — механизм замедления потока для синхронизации producer/consumer.
Резюме
writeFile и appendFile удобны для небольших и простых операций; createWriteStream обязателен при работе с большими объёмами или потоковыми источниками. Всегда обрабатывайте ошибки, выбирайте асинхронные API для неблокирующих приложений и закрывайте потоки для корректного завершения записи.
Похожие материалы
Сброс пароля iPhone и iPad — подробное руководство
Сброс пароля в React и Express — пример и рекомендации
Изменить пароль Windows через net user
Исправить iPhone Unavailable — 4 проверенных способа
Разблокировать отключённый iPhone — 4 метода