__dirname和./在node.js中有什么区别?

589

在 Node.js 编程时,如果引用的文件与当前目录有关联,是否有理由使用 __dirname 变量而不是普通的 ./ 呢?到目前为止,我一直在我的代码中使用 ./,刚刚发现了 __dirname 的存在,想知道将我的 ./'s 转换为 __dirname 是否明智,如果是,为什么这是一个明智的想法。


66
简而言之,“./”和“process.cwd()”指的是调用脚本的终端当前目录,而“__dirname”指的是脚本所存储的目录。 - Gui Imamura
9
除非在 require 中使用 .,否则 require 中的路径始终相对于调用 require 的文件。 - Govind Rai
2个回答

943

要点概述

在Node.js中,__dirname始终代表当前正在执行的脚本所在的目录(参见此处)。因此,如果在 /d1/d2/myscript.js 文件中键入 __dirname,则其值将为 /d1/d2

相比之下,.会给出你在终端窗口中使用 node 命令时的目录(即你的工作目录),当你使用像 pathfs 这样的库时。从技术上讲,它最初是你的工作目录,但可以使用 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中的路径始终相对于调用它的文件,与您的工作目录无关。


6
我同意,我会更改采纳的答案。请记住,这个答案是在原先被采纳的答案之后2.5年才加入的,而我直到现在(又过了2年)才注意到它。 :) 迟到总比不到好! - thisissami
17
值得注意的是,./并不总是Node.js启动时当前的目录。它最初确实是这样,但是可以通过process.chdir()更改。因此,./始终是当前工作目录,通常是Node.js启动时的目录,除非您的代码显式更改了工作目录。 - gilly3
3
关于require部分中使用"."的问题,我有点困惑。如果require中的路径始终相对于正在调用的文件,那么路径不应该是require('../thefile')而不是require('../dir1/thefile')吗?我认为“..”已经将路径从dir2带回至dir1的当前位置了。您是否仍需要在路径中加入dir1或者是我误解了某些内容? - andromada
1
如果您需要在某个脚本中使用 ../someDir,并且您将从不同的文件夹运行该命令,那么您该怎么做呢? - cbdeveloper
请注意,使用ES模块时,__dirname全局变量已经被移除,但可以通过import { dirname } from "path";进行替换。 - Robin Métral

161

./ 表示当前工作目录,但在 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'));

如果我进入/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./会被解析为当前工作目录(在本例中为/home/user/)。而/home/user/files/somefile.txt并不存在。


哦,我以为__dirname是当前工作目录...感谢您的澄清! - thisissami
1
有没有办法使用fs引用应用程序的工作目录?例如,我正在尝试从工作目录/movies加载文件,但由于我的模块在文件/custom_modules/中,__dirname会尝试从/custom_modules/movies获取电影。 - user3818284
4
你可以使用./process.cwd()。参见http://nodejs.org/api/process.html#process_process_cwd - fent
值得注意的是,在 require 语句中使用 __dirname 而不是 ./ 不是一个好主意,因为虽然它们在 Node 中的行为相同,但对于那些可以轻松避免的包的 browserify 构建可能会导致问题。 - Jed Watson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接