تكتب fs.writeFile(path, data, callback) نصًا أو Buffer في ملف. إذا لم يكن الملف موجودًا ينشئه Node؛ وإذا كان موجودًا يُستبدل محتواه القديم. وتفعل fs.writeFileSync(path, data) الشيء نفسه وتنتظر حتى تنتهي الكتابة، أما fs.appendFile فتضيف إلى نهاية الملف بدلًا من استبداله.
يطبع saved ثم النص الذي قرأه من جديد؛ ولا يستقبل الـ callback إلا خطأ (أو null)، لا البيانات أبدًا. مرّر 42 بدلًا من النص فيرمي الاستدعاء TypeError: يجب أن تكون البيانات نصًا أو Buffer.
writeFile وwriteFileSync وfs/promises
تأخذ الصيغ الثلاث الوسائط نفسها، وتختلف في طريقة انتظار النتيجة.
const fs = require('fs');
const fsp = require('fs/promises');
fs.writeFileSync('a.txt', 'one'); // blocks, throws on error
fs.writeFile('b.txt', 'two', (err) => {}); // callback with err
await fsp.writeFile('c.txt', 'three'); // promise, use in async code
استخدم writeFileSync في السكربتات وشيفرة بدء التشغيل، ونسخة الوعد في الخوادم، حيث تحجب الكتابة المتزامنة كل الطلبات الأخرى حتى ينتهي القرص. تعرض صفحة fs/promises بقية واجهة الوعود.
الإضافة إلى ملف عبر appendFile
تستبدل writeFile الملف كله. لإضافة سطر إلى سجل، استخدم appendFile، التي تنشئ الملف أيضًا في المرة الأولى.
تطبع القراءة الأولى "second\n"، لأن writeFileSync الثانية استبدلت first، وتطبع الثانية "second\nthird\nfourth\n" (يجعل JSON.stringify الأسطر الجديدة ظاهرة). أضف \n بنفسك: لا تضيفه أي من الدالتين.
writeFile | appendFile | |
|---|---|---|
| الملف غير موجود | تنشئه | تنشئه |
| الملف موجود | تستبدل المحتوى | تضيف إلى النهاية |
| الخيار الافتراضي | 'w' | 'a' |
| الاستخدام المعتاد | حفظ مستند كامل أو JSON | السجلات، سطرًا في كل مرة |
لا تكتب فوق الملف: الخيار flag
يمكن أن يكون الوسيط الثالث كائن خيارات. خاصيته flag تحدد ما يحدث لملف موجود. القيمة 'wx' تعني "اكتب، لكن افشل إن كان الملف موجودًا"، وهي الطريقة الآمنة لإنشاء ملف مرة واحدة فقط.
يفشل الاستدعاء الثاني بـ EEXIST، فيبقى الملف حاويًا abc123. غيّر اسم الملف في الاستدعاء الثاني إلى id2.txt فيطبع الاستدعاءان created.
الخيارات التي ستصادفها أكثر: 'w' (الافتراضي، استبدال)، و'a' (إضافة)، و'wx' (إنشاء فقط)، و'ax' (إضافة، لكن إلى ملف جديد فقط).
التحقق بـ fs.existsSync أولًا ثم الكتابة يترك ثغرة: قد تنشئ عملية أخرى الملف بين الفحص والكتابة. أما 'wx' فتنجز الأمرين في خطوة واحدة.
كتابة JSON في ملف
لا تقبل writeFile الكائنات. حوّلها إلى نص بـ JSON.stringify؛ والوسيط الثالث، 2، يضيف مسافات بادئة للناتج ليكون الملف مقروءًا.
يحمل الملف الكائن على عدة أسطر بمسافات بادئة، وتحليله من جديد يعطي كائنًا مساويًا، فيطبع السطر الأخير 2. مرّر الكائن دون JSON.stringify فيرمي الاستدعاء TypeError.
أنشئ المجلد أولًا عبر mkdir
تنشئ writeFile الملفات لا المجلدات. الكتابة إلى reports/2026/june.txt حين لا يكون reports موجودًا تفشل بـ ENOENT. أنشئ المسار أولًا بـ mkdir مع { recursive: true }، التي تنشئ كل مجلد ناقص ولا تفعل شيئًا إن كانت المجلدات موجودة.
تفشل الكتابة الأولى بـ ENOENT؛ وبعد mkdir تنجح الكتابة نفسها وتسرد readdir القيمة [ 'june.txt' ]. ابنِ هذه المسارات بـ path.join في الشيفرة الحقيقية لتعمل على Windows أيضًا.
أخطاء شائعة
افتراض أن الملف كُتب مباشرة بعد الاستدعاء. تعود fs.writeFile قبل أن تصل البيانات إلى القرص. اقرأ الملف أو ابدأ الخطوة التالية داخل الـ callback، أو انتظر نسخة الوعد بـ await.
فقدان البيانات بالكتابة داخل حلقة. استدعاء writeFile مرة لكل عنصر يستبدل الملف في كل مرة، فلا يبقى إلا العنصر الأخير. استخدم appendFile، أو ابنِ النص كاملًا واكتبه مرة واحدة.
كتابة [object Object]. تمرير كائن عبر String() أو قالب نصي يكتب [object Object]. استخدم JSON.stringify.
الأسئلة الشائعة
هل تكتب fs.writeFile فوق الملف؟
نعم. مع الخيار الافتراضي 'w' تفرّغ الملف وتكتب البيانات الجديدة، فيضيع المحتوى القديم. مرّر { flag: 'a' } أو استخدم appendFile للإضافة إلى النهاية بدلًا من ذلك.
هل تنشئ fs.writeFile الملف إن لم يكن موجودًا؟
نعم، تنشئ الملف. لكنها لا تنشئ المجلدات الناقصة: الكتابة إلى logs/app.log حين لا يكون logs موجودًا تفشل بـ ENOENT.
ماذا يمكنني أن أمرر كبيانات؟
نصًا أو Buffer أو مصفوفة typed array. أي شيء آخر، مثل كائن أو رقم، يرمي TypeError، فحوّل الكائنات بـ JSON.stringify والأرقام بـ String() أولًا.
هل استدعاء writeFile مرات كثيرة في الوقت نفسه على الملف نفسه آمن؟
لا. استدعاءان متوازيان لـ writeFile على ملف واحد قد يتداخلان ويتركان محتوى مختلطًا. انتظر انتهاء أحدهما قبل بدء التالي، أو اجمع البيانات واكتبها مرة واحدة.