Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

浅析 NodeJs 的几种文件路径 #48

Closed
imsobear opened this issue Oct 22, 2014 · 40 comments

Comments

@imsobear
Copy link
Owner

commented Oct 22, 2014

一、挖坑 & 掉坑:

缘起一段这样的代码:

fs.readFile('./docs/use.md', function (err, buffer) {
    if (err) {
      return console.log('error: ', err);
    }

    console.log('OK');
  });

本地运行时一切 OK,线上部署时却死活找不到 ./docs/use.md 这个文件,后来才发现是因为线上启动应用时不是从当前目录启动了,不过为什么启动脚本的位置也会影响这个路径呢,且往下看。

二、填坑:

Node 中的文件路径大概有 __dirname, __filename, process.cwd(), ./ 或者 ../,前三个都是绝对路径,为了便于比较,./../ 我们通过 path.resolve('./')来转换为绝对路径。

先看一个简单的栗子:

假如我们有这样的文件结构:

app/
    -lib/
        -common.js
    -model
        -task.js
        -test.js

在 task.js 里编写如下的代码:

var path = require('path');

console.log(__dirname);
console.log(__filename);
console.log(process.cwd());
console.log(path.resolve('./'));

model 目录下运行 node task.js 得到的输出是:

/Users/guo/Sites/learn/app/model
/Users/guo/Sites/learn/app/model/task.js
/Users/guo/Sites/learn/app/model
/Users/guo/Sites/learn/app/model

然后在 app 目录下运行 node model/task.js,得到的输出是:

/Users/guo/Sites/learn/app/model
/Users/guo/Sites/learn/app/model/task.js
/Users/guo/Sites/learn/app
/Users/guo/Sites/learn/app

那么,不好意思不是问题来了~T_T,我们可以得出一些肤浅的结论了:

  • __dirname: 总是返回被执行的 js 所在文件夹的绝对路径
  • __filename: 总是返回被执行的 js 的绝对路径
  • process.cwd(): 总是返回运行 node 命令时所在的文件夹的绝对路径
  • ./: 跟 process.cwd() 一样、一样、一样的吗?

我明明记得在 require('../lib/common') 里一直都是各种相对路径写,也没见报什么错啊,我们还在再来个栗子吧,还是上面的结构,'model/task.js' 里的代码改成:

var fs = require('fs');
var common = require('../lib/common');

fs.readFile('../lib/common.js', function (err, data) {
    if (err) return console.log(err);
    console.log(data);
});

在 model 目录下运行 node task.js,一切 Ok,没有报错。然后在 app 目录下运行 node model/task.js,然后很果断滴报错了:

那么这下问题真的都是来了,按照上面的理论,在 app 下运行时,../lib/common.js 会被转成 /Users/guo/Sites/learn/lib/common.js,这个路径显然是不存在的,但是从运行结果可以看出 require('../lib/common') 是 OK 的,只是 readFile 时报错了。

那么关于 ./ 正确的结论是:

require() 中使用是跟 __dirname 的效果相同,不会因为启动脚本的目录不一样而改变,在其他情况下跟 process.cwd() 效果相同,是相对于启动脚本所在目录的路径。

三、总结:

只有在 require() 时才使用相对路径(./, ../) 的写法,其他地方一律使用绝对路径,如下:

// 当前目录下
path.dirname(__filename) + '/test.js';
// 相邻目录下
path.resolve(__dirname, '../lib/common.js');

四、参考链接:

以上😄

@imsobear imsobear added the 技术 label Oct 22, 2014

@imsobear imsobear changed the title 浅析 Node 的几种文件路径 浅析 NodeJs 的几种文件路径 Oct 22, 2014

@imsobear

This comment has been minimized.

Copy link
Owner Author

commented Oct 22, 2014

关于 require()../ 这种相对路径做了什么特殊处理没有研究,后续可以再补充一下~

@chaosforfun

This comment has been minimized.

Copy link

commented May 5, 2015

好吧,感谢填坑。

@ChangMM

This comment has been minimized.

Copy link

commented Jul 24, 2015

@bhtbed

This comment has been minimized.

Copy link

commented Sep 7, 2015

其实原因很简单,require的路径必须是相对于当前执行文件的,否则你引用的node_module,它的require路径肯定不能够正确识别了呀。

@Pines-Cheng

This comment has been minimized.

Copy link

commented Nov 19, 2015

感谢填坑!

@pfan123

This comment has been minimized.

Copy link

commented Jan 3, 2016

有些地方的路径楼主写错了,请更正一下

@lamda-lin

This comment has been minimized.

Copy link

commented Jul 3, 2016

感谢躺坑

@hefei00

This comment has been minimized.

Copy link

commented Jul 14, 2016

写node的新人,这两天遇到了路径问题,多谢。

@gb-6k-house

This comment has been minimized.

Copy link

commented Jul 21, 2016

此坑早已踩!!!

@heysdc

This comment has been minimized.

Copy link

commented Aug 4, 2016

在坑里站了一晚上,刚找到原因顺藤摸瓜看到了这篇分析,我泪流满面

@qianzhangsheng

This comment has been minimized.

Copy link

commented Aug 8, 2016

好文,谢谢博主

@ghost

This comment has been minimized.

Copy link

commented Aug 29, 2016

赞。

@tigerLVU

This comment has been minimized.

Copy link

commented Sep 2, 2016

@tonygemcd

This comment has been minimized.

Copy link

commented Sep 5, 2016

👍

@Gringe920

This comment has been minimized.

Copy link

commented Nov 3, 2016

呜呜菜鸟表示看不大懂

@Akiq2016

This comment has been minimized.

Copy link

commented Dec 20, 2016

thank you!

@Sirormy

This comment has been minimized.

Copy link

commented Dec 21, 2016

文件结构是不是model应该改成model.js啊, 跟输出的文件路径不匹配呢

@hacke2

This comment has been minimized.

Copy link

commented Jan 17, 2017

对于文件地址的凭借最好使用path.join,可以屏蔽各个操作系统之前的差异

@xiaozhouwu

This comment has been minimized.

Copy link

commented Jan 18, 2017

model写成model.js了你...

@jiapeiyang

This comment has been minimized.

Copy link

commented Jan 19, 2017

感谢填坑!

@Mr0Lz

This comment has been minimized.

Copy link

commented Jan 23, 2017

谢谢

@sevencai

This comment has been minimized.

Copy link

commented Mar 9, 2017

/Users/guo/Sites/learn/app/model.js
/Users/guo/Sites/learn/app/model.js/task.js

=》应该是

/Users/guo/Sites/learn/app/model
/Users/guo/Sites/learn/app/model/task.js

@imsobear imsobear closed this Apr 5, 2017

@Hellowor1d

This comment has been minimized.

Copy link

commented Apr 14, 2017

一个很有营养的坑 :)

@kokokele

This comment has been minimized.

Copy link

commented Apr 25, 2017

只有在 require() 时才使用相对路径(./, ../) 的写法,其他地方一律使用绝对路径,如下:

// 当前目录下
path.dirname(__filename) + '/test.js';
// 相邻目录下
path.resolve(__dirname, '../lib/common.js');


应该是:
// 当前目录下
path.dirname(__dirname) + '/test.js';

@WinjayYu

This comment has been minimized.

Copy link

commented May 4, 2017

谢谢分享

@ly525

This comment has been minimized.

Copy link

commented May 5, 2017

建议看下@sevencai的建议, 修改下代码吧

@imsobear

This comment has been minimized.

Copy link
Owner Author

commented May 5, 2017

@liuyanshi @sevencai 已修正,谢谢反馈。

@winterJIE

This comment has been minimized.

Copy link

commented Jul 14, 2017

搜问题竟然搜到了果大的文章,厉害!

@Yhspehy

This comment has been minimized.

Copy link

commented Jul 20, 2017

@kokokele
path.dirname()获得的是filename所在文件夹的地址,
所以是path.dirname(_filename) + '/test.js'

@johnlin0207

This comment has been minimized.

Copy link

commented Oct 17, 2017

回头试试再回来赞

@ghost

This comment has been minimized.

Copy link

commented Nov 5, 2017

process.cwd()也比较好理解,表示的是node进程当前所在的路径,因为只有你在一个目录下执行node *.js,才会启动一个node进程。所以说,总是返回运行 node 命令时所在的文件夹的绝对路径。path.resolve相当于对resolve函数的每一个参数都执行cd命令。例如,path.resolve('./'),而且只有你在一个目录下执行node ./**/*.js(执行一系列的cd命令操作,然后运行node ./**/*.js),path.resolve('./')才可能被执行(path.resolve('./')可能存在你执行node操作的js文件中或者存在你执行node操作的js文件且通过require进来的js文件中),这恰恰说明你执行cd操作已经结束啦。所以说path.resolve('./')的参考点就是你执行node ./**/*.js时的路径

@SuperAL

This comment has been minimized.

Copy link

commented Nov 8, 2017

When using require, the path is relative to that source file (NOT root directory).
When using fs, the path is relative to process.cwd() (NOT that source file).
Relative path when using require and fs for node.js

@pengliheng

This comment has been minimized.

Copy link

commented Nov 8, 2017

谢谢,一步一步爬坑中..........

@mrzxc

This comment has been minimized.

Copy link

commented Dec 6, 2017

thanks. let us climb out of the pits. 么么哒

@Jiaaa1014

This comment has been minimized.

Copy link

commented Jan 1, 2018

謝謝

@qiaoqiaowang

This comment has been minimized.

Copy link

commented Mar 19, 2018

多谢填坑

@hollownewman

This comment has been minimized.

Copy link

commented Sep 10, 2018

很好的文章,收获多,赞一下。已保存。

@johnnyZTY

This comment has been minimized.

Copy link

commented Dec 5, 2018

thanks

1 similar comment
@lucker-lv

This comment has been minimized.

Copy link

commented Mar 26, 2019

thanks

@wuyaoqing

This comment has been minimized.

Copy link

commented May 7, 2019

nice 刚刚踩这个坑

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
You can’t perform that action at this time.