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

ב-ES modules אין __dirname; שימוש בו זורק 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'. לפני שאתם קוראים קובץ ששמו הגיע מבקשה, עשו לנתיב resolve ובדקו שהוא עדיין מתחיל בתיקייה שלכם.

שאלות נפוצות

מה ההבדל בין __dirname ל-process.cwd()?

__dirname היא התיקייה של קובץ המקור הנוכחי, והיא אף פעם לא משתנה. process.cwd() היא התיקייה שממנה המשתמש הריץ את node. הן זהות רק כשהתוכנית מופעלת מהתיקייה שלה.

להשתמש ב-path.join או ב-path.resolve עם __dirname?

שתיהן עובדות עבור path.join(__dirname, 'data.json'), כי __dirname כבר מוחלט. השתמשו ב-resolve כשקטע מסוים עשוי להיות מוחלט בעצמו, למשל נתיב שהמשתמש הקליד, ואתם רוצים שהנתיב הזה יקבע.

איך משתמשים במודול path עם כתובות URL?

לא משתמשים: כתובות URL תמיד משתמשות ב-/ ויש להן כללים משלהן ל-.. ול-query strings. השתמשו במחלקה URL, כמו ב-new URL('../img/logo.png', 'https://example.com/docs/page').

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל