دليل Node.js ، الجزء 9: العمل مع نظام الملفات

اليوم ، في الجزء التاسع من ترجمة البرنامج التعليمي Node.js ، سنتحدث عن العمل مع الملفات. على وجه الخصوص ، سنتحدث عن وحدات fs ووحدات المسار - عن واصفات الملفات ، وعن مسارات الملفات ، وعن الحصول على معلومات حول الملفات ، وقراءتها وكتابتها ، والعمل مع الدلائل.




العمل مع واصفات الملف في Node.js


قبل أن تتمكن من التفاعل مع الملفات الموجودة في نظام الملفات الخاص بخادمك ، تحتاج إلى الحصول على واصف ملف.

يمكن الحصول على الواصف باستخدام طريقة open() غير المتزامنة من الوحدة النمطية fs لفتح الملف:

 const fs = require('fs') fs.open('/Users/flavio/test.txt', 'r', (err, fd) => { //fd -    }) 

لاحظ المعلمة الثانية ، r ، المستخدمة عند استدعاء الأسلوب fs.open() . هذه علامة تخبر النظام أن الملف مفتوح للقراءة. فيما يلي بعض العلامات التي يتم استخدامها غالبًا عند العمل مع هذا وبعض الطرق الأخرى:

  • r+ - فتح الملف للقراءة والكتابة.
  • w+ - فتح الملف للقراءة والكتابة عن طريق ضبط مؤشر الدفق على بداية الملف. إذا كان الملف غير موجود ، يتم إنشاؤه.
  • a فتح الملف للكتابة عن طريق تعيين مؤشر الدفق إلى نهاية الملف. إذا كان الملف غير موجود ، يتم إنشاؤه.
  • a+ - فتح الملف للقراءة والكتابة عن طريق تعيين مؤشر الدفق إلى نهاية الملف. إذا كان الملف غير موجود ، يتم إنشاؤه.

يمكن فتح الملفات باستخدام الطريقة المتزامنة fs.openSync() ، والتي بدلاً من توفير واصف ملف في رد الاتصال ، تقوم بإرجاعه:

 const fs = require('fs') try { const fd = fs.openSync('/Users/flavio/test.txt', 'r') } catch (err) { console.error(err) } 

بعد استلام الواصف باستخدام أي من الأساليب المذكورة أعلاه ، يمكنك إجراء العمليات اللازمة معه.

بيانات الملف


يحتوي كل ملف على مجموعة بيانات مرتبطة به ؛ يمكنك فحص هذه البيانات باستخدام Node.js. على وجه الخصوص ، يمكن القيام بذلك باستخدام طريقة stat() من وحدة fs .

تُسمى هذه الطريقة بتمرير المسار إلى الملف ، وبعد أن يتلقى Node.js المعلومات الضرورية حول الملف ، سيتم استدعاء الاستدعاء الذي تم تمريره إلى الأسلوب stat() . إليك ما يبدو عليه:

 const fs = require('fs') fs.stat('/Users/flavio/test.txt', (err, stats) => { if (err) {   console.error(err)   return } //      `stats` }) 

Node.js لديه القدرة على استرداد معلومات الملف بشكل متزامن. مع هذا النهج ، يتم حظر مؤشر الترابط الرئيسي حتى يتم الحصول على خصائص الملف:

 const fs = require('fs') try { const stats = fs.statSync ('/Users/flavio/test.txt') } catch (err) { console.error(err) } 

ستقع المعلومات حول الملف في ثابت stats . ما هذه المعلومات؟ في الواقع ، يزودنا الكائن المقابل بعدد كبير من الخصائص والأساليب المفيدة:

  • .isFile() و. .isDirectory() ، على التوالي ، بمعرفة ما إذا كان الملف الذي تم التحقيق فيه هو ملف عادي أو دليل.
  • تتيح لك طريقة .isSymbolicLink() معرفة ما إذا كان الملف هو ارتباط رمزي.
  • يمكن العثور على حجم الملف باستخدام خاصية .size .

هناك طرق أخرى هنا ، ولكن هذه هي الأكثر استخدامًا. إليك كيفية استخدامها:

 const fs = require('fs') fs.stat('/Users/flavio/test.txt', (err, stats) => { if (err) {   console.error(err)   return } stats.isFile() //true stats.isDirectory() //false stats.isSymbolicLink() //false stats.size //1024000 //= 1MB }) 

مسارات الملفات في Node.js ووحدة المسار


مسار الملف هو عنوان المكان الموجود في نظام الملفات.

على Linux و macOS ، قد يبدو المسار كما يلي:

 /users/flavio/file.txt 

في Windows ، تبدو المسارات مختلفة قليلاً:

 C:\users\flavio\file.txt 

يجب ملاحظة الاختلافات في تنسيقات تسجيل المسار عند استخدام أنظمة تشغيل مختلفة ، نظرًا لنظام التشغيل المستخدم لنشر خادم Node.js.

يحتوي Node.js على وحدة path قياسية مصممة للعمل مع مسارات الملفات. قبل استخدام هذه الوحدة في البرنامج ، يجب توصيلها:

 const path = require('path') 

▍ الحصول على معلومات مسار الملف


إذا كان لديك مسار للملف ، فعندئذٍ باستخدام إمكانيات وحدة path ، يمكنك ، في شكل ملائم للإدراك والمعالجة الإضافية ، معرفة تفاصيل حول هذا المسار. يبدو هذا:

 const notes = '/users/flavio/notes.txt' path.dirname(notes) // /users/flavio path.basename(notes) // notes.txt path.extname(notes) // .txt 

هنا ، في سطر notes ، يتم تخزين مسار الملف. تم استخدام الطرق التالية لوحدة path لتحليل path :

  • dirname() - إرجاع الدليل الأصلي للملف.
  • basename() - إرجاع اسم الملف.
  • extname() - إرجاع ملحق الملف.

يمكنك معرفة اسم الملف بدون الامتداد عن طريق استدعاء طريقة .basename() وتمريرها الوسيطة الثانية التي تمثل الامتداد:

 path.basename(notes, path.extname(notes)) //notes 

with العمل مع مسارات الملفات


يمكن دمج عدة أجزاء من المسار باستخدام طريقة path.join() :

 const name = 'flavio' path.join('/', 'users', name, 'notes.txt') //'/users/flavio/notes.txt' 

يمكنك العثور على المسار المطلق للملف بناءً على المسار النسبي إليه باستخدام الطريقة path.resolve() :

 path.resolve('flavio.txt') //'/Users/flavio/flavio.txt'       

في هذه الحالة ، يضيف Node.js ببساطة /flavio.txt إلى المسار المؤدي إلى دليل العمل الحالي. إذا قمت ، عند استدعاء هذه الطريقة ، بتمرير معلمة أخرى تمثل المسار إلى المجلد ، فإن الطريقة تستخدمه كأساس لتحديد المسار المطلق:

 path.resolve('tmp', 'flavio.txt') // '/Users/flavio/tmp/flavio.txt'       

إذا كان المسار يمر كمعلمة أولى تبدأ بخط مائل ، فهذا يعني أنه مسار مطلق.

 path.resolve('/etc', 'flavio.txt') // '/etc/flavio.txt' 

هنا طريقة أخرى مفيدة - path.normalize() . يسمح لك بإيجاد المسار الحقيقي للملف باستخدام المسار الذي يحتوي على مؤهلات المسار النسبي مثل النقطة ( . ) ، نقطتين ( .. ) ، أو خطين مائلين:

 path.normalize('/users/flavio/..//test.txt') // /users/test.txt 

لا تتحقق طريقتا resolve() normalize() من وجود دليل. إنهم ببساطة يجدون المسار بناءً على البيانات التي تم تمريرها إليهم.

قراءة الملفات في Node.js


أسهل طريقة لقراءة الملفات في Node.js هي استخدام طريقة fs.readFile() ، وتمريرها إلى الملف والاستدعاء ، والذي سيتم استدعاؤه بتمرير بيانات الملف (أو كائن الخطأ) إليه:

 fs.readFile('/Users/flavio/test.txt', (err, data) => { if (err) {   console.error(err)   return } console.log(data) }) 

إذا لزم الأمر ، يمكنك استخدام الإصدار المتزامن من هذه الطريقة - fs.readFileSync() :

 const fs = require('fs') try { const data = fs.readFileSync('/Users/flavio/test.txt') console.log(data) } catch (err) { console.error(err) } 

بشكل افتراضي ، يتم استخدام ترميز utf8 عند قراءة الملفات ، ولكن يمكن أيضًا تعيين الترميز بشكل مستقل عن طريق تمرير المعلمة المناسبة إلى الطريقة.

fs.readFile() و fs.readFileSync() محتويات الملف بالكامل في الذاكرة. وهذا يعني أن العمل مع الملفات الكبيرة باستخدام هذه الأساليب سيؤثر بشكل خطير على استهلاك الذاكرة لتطبيقك وسيؤثر على أدائه. إذا كنت بحاجة إلى العمل مع هذه الملفات ، فمن الأفضل استخدام التدفقات.

كتابة الملفات إلى Node.js


في Node.js ، من الأسهل كتابة الملفات باستخدام طريقة fs.writeFile() :

 const fs = require('fs') const content = 'Some content!' fs.writeFile('/Users/flavio/test.txt', content, (err) => { if (err) {   console.error(err)   return } //   }) 

هناك أيضًا إصدار متزامن من نفس الطريقة - fs.writeFileSync() :

 const fs = require('fs') const content = 'Some content!' try { const data = fs.writeFileSync('/Users/flavio/test.txt', content) //   } catch (err) { console.error(err) } 

تقوم هذه الطرق ، افتراضيًا ، باستبدال محتويات الملفات الموجودة. يمكنك تغيير سلوكهم القياسي باستخدام العلامة المناسبة:

 fs.writeFile('/Users/flavio/test.txt', content, { flag: 'a+' }, (err) => {}) 

يمكن استخدام الأعلام هنا ، والتي قمنا بإدراجها بالفعل في القسم الخاص بالواصفات. يمكن العثور على تفاصيل حول الأعلام هنا .

إرفاق البيانات بملف


fs.appendFile() طريقة fs.appendFile() المتزامن ، fs.appendFileSync() ) بشكل ملائم لإرفاق البيانات في نهاية الملف:

 const content = 'Some content!' fs.appendFile('file.log', content, (err) => { if (err) {   console.error(err)   return } //! }) 

حول استخدام الخيوط


أعلاه ، وصفنا الطرق التي ، عند الكتابة إلى ملف ، كتابة الكمية الكاملة من البيانات المنقولة إليه ، وبعد ذلك ، إذا تم استخدام إصداراتها المتزامنة ، فإنها تعيد التحكم إلى البرنامج ، وإذا تم استخدام إصدارات غير متزامنة ، فإنها تستدعي الاسترجاعات. إذا لم يناسبك هذا الوضع ، فمن الأفضل استخدام التدفقات.

العمل مع الدلائل في Node.js


توفر وحدة fs للمطور العديد من الطرق المناسبة التي يمكن استخدامها للعمل مع الدلائل.

heckتحقق من وجود المجلد


للتحقق مما إذا كان الدليل موجودًا وما إذا كان Node.js يمكنه الوصول إليه ، وفقًا للأذونات ، يمكنك استخدام طريقة fs.access() .

▍ قم بإنشاء مجلد جديد


لإنشاء مجلدات جديدة ، يمكنك استخدام fs.mkdir() و fs.mkdirSync() :

 const fs = require('fs') const folderName = '/Users/flavio/test' try { if (!fs.existsSync(dir)){   fs.mkdirSync(dir) } } catch (err) { console.error(err) } 

▍ قراءة محتويات المجلد


لقراءة محتويات المجلد ، يمكنك استخدام fs.readdir() و fs.readdirSync() . يقرأ هذا المثال محتويات المجلد - أي المعلومات حول الملفات والأدلة الفرعية التي يحتوي عليها ويعيد مساراتها النسبية:

 const fs = require('fs') const path = require('path') const folderPath = '/Users/flavio' fs.readdirSync(folderPath) 

هذه هي الطريقة التي يمكنك من خلالها الحصول على المسار الكامل للملف:

 fs.readdirSync(folderPath).map(fileName => { return path.join(folderPath, fileName) } 

يمكن تصفية النتائج من أجل الحصول على الملفات فقط واستبعادها من إخراج الدليل:

 const isFile = fileName => { return fs.lstatSync(fileName).isFile() } fs.readdirSync(folderPath).map(fileName => { return path.join(folderPath, fileName)).filter(isFile) } 

▍ إعادة تسمية المجلد


يمكنك استخدام fs.rename() و fs.renameSync() لإعادة تسمية المجلد. المعلمة الأولى هي مسار المجلد الحالي ، والثانية مسار جديد:

 const fs = require('fs') fs.rename('/Users/flavio', '/Users/roger', (err) => { if (err) {   console.error(err)   return } // }) 

يمكنك إعادة تسمية المجلد باستخدام الأسلوب المتزامن fs.renameSync() :

 const fs = require('fs') try { fs.renameSync('/Users/flavio', '/Users/roger') } catch (err) { console.error(err) } 

▍ حذف المجلد


لحذف مجلد ، يمكنك استخدام fs.rmdir() أو fs.rmdirSync() . وتجدر الإشارة إلى أن حذف مجلد يحتوي على شيء ما هو مهمة أكثر تعقيدًا من حذف مجلد فارغ. إذا كنت بحاجة إلى حذف هذه المجلدات ، فاستخدم حزمة fs-extra ، والتي تحظى بشعبية كبيرة ودعم جيد. هو بديل للوحدة fs ، وتوسيع قدراتها.

يمكن لطريقة remove() من الحزمة fs-extra حذف المجلدات التي تحتوي بالفعل على شيء ما.

يمكنك تثبيت هذه الوحدة على النحو التالي:

 npm install fs-extra 

هنا مثال على استخدامه:

 const fs = require('fs-extra') const folder = '/Users/flavio' fs.remove(folder, err => { console.error(err) }) 

يمكن استخدام أساليبها في شكل وعود:

 fs.remove(folder).then(() => { // }).catch(err => { console.error(err) }) 

يُعد البناء غير المتزامن / المنتظر مقبولًا أيضًا:

 async function removeFolder(folder) { try {   await fs.remove(folder)   // } catch (err) {   console.error(err) } } const folder = '/Users/flavio' removeFolder(folder) 

وحدة FS


أعلاه ، لقد صادفنا بالفعل بعض طرق وحدة fs التي يتم استخدامها عند العمل مع نظام الملفات. في الواقع ، يحتوي على العديد من الأشياء المفيدة. تذكر أنه لا يحتاج إلى تثبيت ، من أجل استخدامه في البرنامج ، يكفي توصيله:

 const fs = require('fs') 

بعد ذلك ، ستتمكن من الوصول إلى طرقه ، ومن بينها نلاحظ ما يلي ، وبعضها تعرفه بالفعل:

  • fs.access() : للتحقق من وجود ملف والقدرة على الوصول إليه بناءً على الأذونات.
  • fs.appendFile() : fs.appendFile() البيانات بملف. إذا لم يكن الملف موجودًا ، فسيتم إنشاؤه.
  • fs.chmod() : يغير الأذونات لملف معين. طرق مماثلة: fs.lchmod() ، fs.fchmod() .
  • fs.chown() : يغير المالك والمجموعة للملف المحدد. طرق مماثلة: fs.fchown() ، fs.lchown() .
  • fs.close() : لإغلاق واصف الملف.
  • fs.copyFile() : نسخ الملف.
  • fs.createReadStream() : إنشاء دفق لقراءة ملف.
  • fs.createWriteStream() : إنشاء دفق كتابة ملف.
  • fs.link() : إنشاء ارتباط ثابت جديد للملف.
  • fs.mkdir() : إنشاء دليل جديد.
  • fs.mkdtemp() : إنشاء دليل مؤقت.
  • fs.open() : فتح ملف.
  • fs.readdir() : يقرأ محتويات الدليل.
  • fs.readFile() : يقرأ محتويات الملف. طريقة مماثلة: fs.read() .
  • fs.readlink() : يقرأ قيمة الارتباط الرمزي.
  • fs.realpath() : يحل مسار الملف النسبي الذي تم إنشاؤه باستخدام الأحرف . و .. ، في المسار الكامل.
  • fs.rename() : إعادة تسمية ملف أو مجلد.
  • fs.rmdir() : إزالة المجلد.
  • fs.stat() : إرجاع معلومات الملف. طرق مماثلة: fs.fstat() ، fs.lstat() .
  • fs.symlink() : إنشاء ارتباط رمزي جديد للملف.
  • fs.truncate() : يتم اقتطاع الملف إلى الطول المحدد. طريقة مماثلة: fs.ftruncate() .
  • fs.unlink() : إزالة ملف أو ارتباط رمزي.
  • fs.unwatchFile() : تعطيل مراقبة تغييرات الملف.
  • fs.utimes() : يغير الطابع الزمني للملف. طريقة مماثلة: fs.futimes() .
  • fs.watchFile() : تمكين مراقبة تغييرات الملف. طريقة مماثلة: fs.watch() .
  • fs.writeFile() : يكتب البيانات إلى ملف. طريقة مماثلة: fs.write() .

ميزة مثيرة للاهتمام للوحدة النمطية fs هي حقيقة أن جميع طرقها ، بشكل افتراضي ، غير متزامنة ، ولكن هناك أيضًا إصدارات متزامنة منها ، يتم الحصول على أسمائها عن طريق إضافة كلمة Sync إلى أسماء الطرق غير المتزامنة.

على سبيل المثال:

  • fs.rename()
  • fs.renameSync()
  • fs.write()
  • fs.writeSync()

يؤثر استخدام الأساليب المتزامنة بشكل خطير على كيفية عمل البرنامج.

يوفر Node.js 10 الدعم التجريبي لواجهات برمجة التطبيقات المستندة إلى الوعود.

استكشف طريقة fs.rename() . فيما يلي نسخة غير متزامنة من هذه الطريقة باستخدام عمليات الاسترجاعات:

 const fs = require('fs') fs.rename('before.json', 'after.json', (err) => { if (err) {   return console.error(err) } // }) 

عند استخدام نسخته المتزامنة ، يتم استخدام بنية try/catch لمعالجة الأخطاء:

 const fs = require('fs') try { fs.renameSync('before.json', 'after.json') // } catch (err) { console.error(err) } 

الفرق الرئيسي بين هذه الخيارات لاستخدام هذه الطريقة هو أنه في الحالة الثانية ، سيتم حظر البرنامج النصي حتى اكتمال عملية الملف.

وحدة المسار


تحتوي وحدة المسار ، التي تحدثنا عنها أيضًا عن بعض ميزاتها ، على العديد من الأدوات المفيدة التي تسمح لك بالتفاعل مع نظام الملفات. كما ذكرنا من قبل ، لا تحتاج إلى تثبيته ، لأنه جزء من Node.js. من أجل استخدامه ، يكفي توصيله:

 const path = require('path') 

path.sep الخاصية path.sep لهذه الوحدة النمطية الحرف المستخدم لفصل مقاطع المسار ( \ على Windows و / على Linux و path.delimiter ) ، path.delimiter الخاصية path.delimiter الحرف المستخدم لفصل مسارات متعددة ( ; على Windows و : على Linux و macOS).

دعونا نفكر ونوضح بعض طرق وحدة path .

athpath.basename ()


إرجاع الجزء الأخير من المسار. من خلال تمرير المعلمة الثانية إلى هذه الطريقة ، يمكنك إزالة امتداد الملف.

 require('path').basename('/test/something') //something require('path').basename('/test/something.txt') //something.txt require('path').basename('/test/something.txt', '.txt') //something 

athpath.dirname ()


إرجاع جزء المسار الذي يمثل اسم الدليل:

 require('path').dirname('/test/something') // /test require('path').dirname('/test/something/file.txt') // /test/something 

athpath.extname ()


إرجاع جزء من المسار الذي يمثل امتداد الملف:

 require('path').extname('/test/something') // '' require('path').extname('/test/something/file.txt') // '.txt' 

athpath.is المطلق ()


إرجاع صحيح إذا كان المسار مطلقًا:

 require('path').isAbsolute('/test/something') // true require('path').isAbsolute('./test/something') // false 

athpath.join ()


يربط عدة أجزاء من المسار:

 const name = 'flavio' require('path').join('/', 'users', name, 'notes.txt') //'/users/flavio/notes.txt' 

athpath.normalize ()


محاولة معرفة المسار الحقيقي بناءً على المسار الذي يحتوي على الأحرف المستخدمة لبناء المسارات النسبية مثل . و .. و // :

 require('path').normalize('/users/flavio/..//test.txt') ///users/test.txt 

athpath.parse ()


يحول المسار إلى كائن تمثل خصائصه أجزاء فردية من المسار:

  • root : الدليل الجذر.
  • dir : مسار ملف يبدأ من الدليل الجذر
  • base : اسم الملف وامتداده.
  • name : name الملف.
  • ext : امتداد الملف.

إليك مثال باستخدام هذه الطريقة:

 require('path').parse('/users/test.txt') 

نتيجة عمله تم الحصول على الشيء التالي:

 { root: '/', dir: '/users', base: 'test.txt', ext: '.txt', name: 'test' } 

athpath.relative ()


يأخذ ، كحجج ، طريقتين. إرجاع المسار النسبي من المسار الأول إلى الثاني ، بناءً على دليل العمل الحالي:

 require('path').relative('/Users/flavio', '/Users/flavio/test.txt') //'test.txt' require('path').relative('/Users/flavio', '/Users/flavio/something/test.txt') //'something/test.txt' 

athpath.resolve ()


يبحث عن المسار المطلق بناءً على المسار النسبي الذي تم تمريره إليه:

 path.resolve('flavio.txt') //'/Users/flavio/flavio.txt'      . 

الملخص


اليوم نظرنا إلى Node.js fs ووحدات path المستخدمة للعمل مع نظام الملفات. في الجزء التالي من هذه السلسلة ، التي تنتهي عندها ، سنناقش os ، events ، ووحدات http ، ونتحدث عن العمل مع التدفقات وأنظمة إدارة قواعد البيانات في Node.js.

أعزائي القراء! ما هي حزم npm التي تستخدمها عند العمل مع نظام الملفات في Node.js؟

Source: https://habr.com/ru/post/ar424969/


All Articles