В чем разница между __dirname и ./ в node.js?


498

При программировании в Node.js и обращении к файлам, которые находятся где-то относительно вашего текущего каталога, есть ли причина использовать __dirnameпеременную вместо обычной ./? До сих пор я использовал ./ в своем коде и только что обнаружил существование __dirname, и по сути хочу узнать, будет ли разумно конвертировать мои ./ в это, и если да, то почему это будет разумной идеей ,


47
tl; dr: Таким образом, в основном, разница в том, что «./» и «process.cwd ()» относятся к текущему каталогу терминала, вызывающего скрипт, тогда как «__dirname» относится к каталогу, в котором скрипт сохраняются.
Ги Имамура

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
Я немного запутался в использовании. Внутри require part, если путь внутри require всегда относительно файла, который вы вызываете, разве путь не должен быть require ('../ thefile') вместо require ('../ dir1 / thefile')? я подумал ... вернуть текущую позицию пути на один уровень от dir2 к dir1 уже. Вам все еще нужно поместить dir1 в путь или я что-то понял?
Андромада

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
апреля

Стоит отметить, что не стоит использовать __dirname вместо ./ в инструкциях require, поскольку, хотя они ведут себя одинаково в узле, это может вызвать проблемы со сборками browserify для пакетов, которые легко избежать в противном случае.
Джед Уотсон,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.