Яка різниця між __dirname та ./ у node.js?


498

Коли ви програмуєте в Node.js і посилаєтесь на файли, які розташовані десь відносно вашого поточного каталогу, чи є причина використовувати __dirnameзмінну замість просто звичайної ./? Я до сих пір використовував ./ у своєму коді і щойно виявив існування __dirname, і, по суті, хочу знати, чи було б розумно конвертувати мої ./ в це, і якщо так, то чому це було б розумною ідеєю .


47
tl; dr: Отже, в основному різниця полягає в тому, що './' і 'process.cwd ()' посилаються на поточний dir терміналу, що викликає скрипт, тоді як '__dirname' позначає dir, у якому сценарій зберігається.
Gui Imamura

1
За винятком випадків, коли .використовується всередину require. Шлях всередині requireзавжди відносно файлу, що містить виклик до require.
Говінд Рай

Відповіді:


814

Суть

У Node.js - __dirnameце завжди каталог, в якому знаходиться поточний виконуваний сценарій ( див. Це ). Так що, якщо ви ввели __dirnameв /d1/d2/myscript.js, то значення буде /d1/d2.

Навпаки, .дає вам каталог, з якого ви запустили nodeкоманду у вікні вашого терміналу (тобто у робочому каталозі), коли ви використовуєте бібліотеки типу « pathта» fs. Технічно він починається як ваш робочий каталог, але може бути змінений за допомогою process.chdir().

Виняток при використанні .з require(). Шлях всередині requireзавжди відносно файлу, що містить виклик до require.

Наприклад...

Скажімо, структура вашого каталогу

/dir1
  /dir2
    pathtest.js

і pathtest.jsмістить

var path = require("path");
console.log(". = %s", path.resolve("."));
console.log("__dirname = %s", path.resolve(__dirname));

і ви

cd /dir1/dir2
node pathtest.js

Ви отримуєте

. = /dir1/dir2
__dirname = /dir1/dir2

Ваша робоча директорія - /dir1/dir2це те, що .вирішує. Оскільки pathtest.jsзнаходиться в /dir1/dir2тому, що __dirnameвирішує і те.

Однак якщо ви запускаєте сценарій з /dir1

cd /dir1
node dir2/pathtest.js

Ви отримуєте

. = /dir1
__dirname = /dir1/dir2

У цьому випадку ваш робочий каталог був /dir1таким, що .вирішено, але __dirnameвсе ще вирішено /dir1/dir2.

Використання .всередині require...

Якщо всередині у dir2/pathtest.jsвас є requireдзвінок, включіть файл всередині, dir1який би ви завжди робили

require('../thefile')

тому що шлях всередині requireзавжди відносно файлу, в якому ви його викликаєте. Це не має нічого спільного з вашим робочим каталогом.


38
ІМО, це пояснення дещо чіткіше, ніж те, з прийнятої відповіді (ви знаєте, "поточний каталог" є дещо неоднозначним).
втілитися

5
Я згоден. Я зміню прийняту відповідь. Будь ласка, майте на увазі, що цю відповідь було додано через 2,5 роки після прийняття оригіналу, і я лише щойно помітив її (ще через 2 роки). :) Краще пізно, ніж ніколи!
thisissami

14
Варто зазначити, що ./не завжди каталог, з якого запускався вузол. Це починається таким чином, але може бути змінено через process.chdir(). Отже, ./завжди є поточний робочий каталог, з якого зазвичай запускався вузол каталогів, якщо тільки ваш код явно не змінив робочий каталог.
gilly3

3
Я трохи плутаюсь щодо використання. всередині потрібна частина, якщо шлях всередині вимагає завжди відносно файлу, який ви викликаєте, чи не слід вимагати шлях ('../ thefile') замість вимагати ('../ dir1 / thefile')? я думав .. повернути поточне положення шляху на один рівень від dir2 до dir1 вже. Вам все-таки потрібно поставити dir1 на шлях чи я сумую щось зрозумів?
andromada

1
А як би ви зробили, якщо вам потрібно використовувати ../someDirякийсь сценарій, і ви збираєтеся запустити команду з іншої папки?
cbdeveloper

154

./посилається на поточний робочий каталог, за винятком require()функції. При використанні require()він перекладається ./в каталог поточного файлу, який називається. __dirnameце завжди каталог поточного файлу.

Наприклад, із наступною структурою файлів

/home/user/dir/files/config.json

{
  "hello": "world"
}

/home/user/dir/files/somefile.txt

text file

/home/user/dir/dir.js

var fs = require('fs');

console.log(require('./files/config.json'));
console.log(fs.readFileSync('./files/somefile.txt', 'utf8'));

Якщо я cdввійду /home/user/dirі побіжу, node dir.jsя отримаю

{ hello: 'world' }
text file

Але коли я запускаю той самий сценарій, /home/user/я отримую

{ hello: 'world' }

Error: ENOENT, no such file or directory './files/somefile.txt'
    at Object.openSync (fs.js:228:18)
    at Object.readFileSync (fs.js:119:15)
    at Object.<anonymous> (/home/user/dir/dir.js:4:16)
    at Module._compile (module.js:432:26)
    at Object..js (module.js:450:10)
    at Module.load (module.js:351:31)
    at Function._load (module.js:310:12)
    at Array.0 (module.js:470:10)
    at EventEmitter._tickCallback (node.js:192:40)

Використання ./працювало з, requireале не для fs.readFileSync. Це тому fs.readFileSync, що ./перекладається на cwd (в даному випадку /home/user/). І /home/user/files/somefile.txtне існує.


о, я думав, __dirname був поточним робочим каталогом ... дякую за уточнення!
thisissami

Чи є спосіб посилатися на робочий каталог програми за допомогою fs? Наприклад, я намагаюся завантажити файл із робочого каталогу /movies, але оскільки мій модуль знаходиться у файлі /custom_modules/, __dirnameнамагається захопити фільм із,/custom_modules/movies

2
Ви можете використовувати ./або process.cwd(). дивіться nodejs.org/api/process.html#process_process_cwd
fent

Варто зауважити, що не дуже гарно використовувати __dirname over ./ в операторах із вимогою, оскільки, хоча вони поводяться однаково у вузлі, це може спричинити проблеми з переглядами збірок для пакетів, які в іншому випадку легко уникнути.
Джед Уотсон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.