Menu

وحدة path في Node.js: path.join مقابل path.resolve

تبني وحدة path مسارات الملفات وتفككها بالطريقة الصحيحة لنظام التشغيل. تلصق path.join المقاطع ببعضها، وتحوّلها path.resolve إلى مسار مطلق انطلاقًا من المجلد الحالي.

تحتوي هذه الصفحة على محررات قابلة للتشغيل. حرّر، شغّل، وشاهد النتيجة فوراً.

تضم path.join() مقاطع المسار بالفاصل الصحيح وتنظف .. والشرطات المائلة المكررة، لكنها تُبقي النتيجة نسبية إذا بدأت بمقطع نسبي. أما path.resolve() فتقوم بالعمل نفسه بدءًا من المقطع الأخير رجوعًا إلى الأول، وتعيد دائمًا مسارًا مطلقًا: تنطلق من مجلد العمل الحالي، وأي مقطع مطلق في الطريق يبدأ المسار من جديد. استخدم join لبناء مسار، وresolve حين تحتاج مسارًا مطلقًا.

طبع users/ada/notes.txt، ثم users/grace/todo.txt (أزال .. المقطع ada)، ثم /srv/app/public/index.html وsrc/lib/utils.js: اختفت الشرطات الزائدة والمقاطع الفارغة. لا تعامل join المقطع /public/ أبدًا كبداية جديدة؛ هو مجرد المقطع التالي.

path.join مقابل path.resolve

يظهر الفرق حين يبدأ مقطع بـ / أو حين يكون المقطع الأول نسبيًا:

مع وجود /public في الوسط، أنتجت join المسار /srv/app/public/img بينما تخلّصت resolve من كل ما سبقه وأنتجت /public/img؛ وتعامل الاثنان مع .. بالطريقة نفسها. يبيّن السطران الأخيران أن join أبقت public/index.html نسبيًا، بينما جعلته resolve مطلقًا بإضافة المجلد الحالي في بدايته.

path.joinpath.resolve
النتيجةنسبية أو مطلقة، حسب المدخلاتمطلقة دائمًا
مقطع يبدأ بـ /مقطع عادي آخريبدأ المسار من عنده
نقطة البدايةلا شيءمجلد العمل الحالي
دون وسائط'.'مجلد العمل الحالي
الاستخدام المعتادبناء مسار من أجزاءتحويل مدخلات المستخدم أو الإعدادات إلى مسار مطلق

basename وdirname وextname وparse

هذه الدوال تفكك المسار. تنظر إلى النص فقط: لا يلزم أن يكون الملف موجودًا.

طبع cat.final.jpg وcat.final و/home/ada/photos و.jpg: تأخذ extname الجزء الواقع بعد آخر نقطة فقط. تعيد path.parse كل ذلك دفعة واحدة (root وdir وbase وext وname)، وتحوّل path.format كائنًا كهذا إلى نص من جديد.

__dirname و__filename

في ملف CommonJS، __dirname هو المسار المطلق للمجلد الذي يحتوي الملف، و__filename هو الملف نفسه. المسار النسبي مثل 'data.json' يُحسب نسبةً إلى المكان الذي شغّل منه المستخدم node، وهذا ينكسر بمجرد أن يشغّل أحدهم سكربتك من مجلد آخر. ابنِ المسارات من __dirname بدلًا من ذلك:

طبع config.json dark وindex.js. تختلف المسارات الكاملة من جهاز لآخر، ولهذا بالضبط تبنيها بـ path.join(__dirname, ...) بدلًا من كتابتها يدويًا.

__dirname في ES modules: import.meta.dirname

لا يوجد __dirname في ES modules؛ واستخدامه يرمي ReferenceError: __dirname is not defined in ES module scope. منذ Node.js 20.11 حلّ محلهما import.meta.dirname وimport.meta.filename:

طبع index.js وdata/users.json. في نسخ Node.js الأقدم من 20.11، استخرج المجلد من عنوان URL الخاص بالوحدة: path.dirname(fileURLToPath(import.meta.url))، مع fileURLToPath من node:url.

لماذا لا تضم المسارات بالنصوص

'data' + '/' + file يعمل على macOS وLinux، ثم يفشل على Windows حيث الفاصل هو \، ولا يفعل شيئًا حيال .. أو الشرطات المكررة أو الشرطة الناقصة. تستخدم path قواعد النظام الذي تعمل عليه. ويمكنك رؤية نتيجة Windows من أي جهاز عبر path.win32:

const path = require('path');

path.posix.join('users', 'ada', 'notes.txt'); // 'users/ada/notes.txt'
path.win32.join('users', 'ada', 'notes.txt'); // 'users\\ada\\notes.txt'
path.sep;                                     // '/' on macOS and Linux, '\\' on Windows

مرّر نتيجة path.join إلى fs.readFile وستقرأ الشيفرة نفسها الملف على كل نظام.

أخطاء شائعة

توقّع أن extname تعرف الامتدادات المزدوجة. path.extname('archive.tar.gz') هي '.gz'، والملف الذي يبدأ بنقطة مثل .env لا امتداد له أصلًا: path.extname('.env') هي ''. افحص نهاية الاسم بنفسك حين تهمك اللاحقة كاملة.

الوثوق بأن join تُبقي المستخدم داخل مجلد. path.join('/srv/app', '../../etc/passwd') هي '/etc/passwd'. قبل أن تقرأ ملفًا يحدد اسمه طلبٌ ما، حلّ المسار وتحقق من أنه ما زال يبدأ بمجلدك.

الأسئلة الشائعة

ما الفرق بين __dirname وprocess.cwd()؟

__dirname هو مجلد ملف الشيفرة الحالي ولا يتغير أبدًا. وprocess.cwd() هو المجلد الذي شغّل منه المستخدم node. لا يتطابقان إلا حين يُشغَّل البرنامج من مجلده هو.

هل أستخدم path.join أم path.resolve مع __dirname؟

كلاهما يعمل في path.join(__dirname, 'data.json')، لأن __dirname مطلق أصلًا. استخدم resolve حين قد يكون أحد المقاطع مطلقًا بنفسه، مثل مسار كتبه المستخدم، وتريد أن تكون له الأولوية.

كيف أستخدم وحدة path مع عناوين URL؟

لا تستخدمها: تستعمل عناوين URL دائمًا / ولها قواعدها الخاصة مع .. وسلاسل الاستعلام. استخدم الصنف URL، كما في new URL('../img/logo.png', 'https://example.com/docs/page').

رسم توضيحي للغات البرمجة في Coddy

تعلّم البرمجة مع Coddy

ابدأ الآن