原文收录在个人 GitHub博客 (https://github.com/jawil/blog) ,喜欢的能够关注最新动态,你们一块儿多交流学习,共同进步,以学习者的身份写博客,记录点滴。html
最近在学习Node.js
里面的fs
模块,遇到了一个比较诡异的现象,踩到了坑,就是读取当前目录下的一个文件,死活读取不到,因为以前对于Node.js
里面的path
模块也不太熟悉,也没系统研究过,因此今天就踩了这个坑,记录踩坑的过程,防止之后踩坑和你们也踩坑。node
说一下当时的情形:git
我纳闷的很半天,我明明就是读取当前目录下的1.findLargest.js
,为何提示找不到这个文件,运行了几遍,死活找不到1.findLargest.js
这个文件。github
后来才发现是由于运行这个文件不是从当前目录运行了,从图中能够看出,当前的目录是/Users/jawil/Desktop/nodejs/demo/ES6-lottery/syntax/nodejs
,而我运行这个脚本的目录是/Users/jawil/Desktop/nodejs/demo/ES6-lottery
;这就是问题的所在了。不过为何运行脚本的位置也会影响这个路径呢,且往下看。学习
计算机不会欺骗人,一切按照规则执行,说找不到这个文件,那确定就是真的找不到,至于为何找不到,那就是由于咱们理解有误差,我最初理解的'./'是当前执行js
文件所在的文件夹的绝对路径,而后Node.js
的理解却不是这样的,咱们慢慢往下看。ui
Node.js
中的文件路径大概有 __dirname
, __filename
, process.cwd()
, ./
或者 ../
,前三个都是绝对路径,为了便于比较,./
和 ../
咱们经过 path.resolve('./')
来转换为绝对路径。spa
简单说一下这几个路径的意思,:翻译
__dirname: 得到当前执行文件所在目录的完整目录名 __filename: 得到当前执行文件的带有完整绝对路径的文件名 process.cwd():得到当前执行node命令时候的文件夹目录名 ./: 文件所在目录
先看一看我电脑当前的目录结构:code
syntax/ -nodejs/ -1.findLargest.js -2.path.js -3.fs.js -regs -regx.js -test.txt
在 path.js 里面咱们写这些代码,看看输出是什么:htm
const path = require('path') console.log('__dirname:', __dirname) console.log('__filename:', __filename) console.log('process.cwd():', process.cwd()) console.log('./:', path.resolve('./'))
在当前目录下也就是nodejs
目录运行 node path.js
,咱们看看输出结果:
__dirname: /Users/jawil/Desktop/nodejs/demo/ES6-lottery/syntax/nodejs __filename: /Users/jawil/Desktop/nodejs/demo/ES6-lottery/syntax/nodejs/2.path.js process.cwd(): /Users/jawil/Desktop/nodejs/demo/ES6-lottery/syntax/nodejs ./: /Users/jawil/Desktop/nodejs/demo/ES6-lottery/syntax/nodejs
而后在 项目根目录ES6-lottery
目录下运行 node syntax/nodejs/2.path.js
,咱们再来看看输出结果:
__dirname: /Users/jawil/Desktop/nodejs/demo/ES6-lottery/syntax/nodejs __filename: /Users/jawil/Desktop/nodejs/demo/ES6-lottery/syntax/nodejs/2.path.js process.cwd(): /Users/jawil/Desktop/nodejs/demo/ES6-lottery ./: /Users/jawil/Desktop/nodejs/demo/ES6-lottery
答案显而易见?咱们能够经过上面的例子对比,暂时得出表面的结论:
__dirname: 老是返回被执行的 js 所在文件夹的绝对路径
__filename: 老是返回被执行的 js 的绝对路径
process.cwd(): 老是返回运行 node 命令时所在的文件夹的绝对路径
./: 跟 process.cwd() 同样,返回 node 命令时所在的文件夹的绝对路径
可是,咱们再来看看这个例子,咱们在上面的例子加几句代码,而后:
咱们在1.findLargest.js
先加这句代码
exports.A = 1;
再来在刚才报错的3.fs.js
里面加这两句代码看看:
const test = require('./1.findLargest.js'); console.log(test)
运行node syntax/nodejs/3.fs.js
,最后看看结果:
为何都是读取./1.findLargest.js
文件,同样的路径,为何require
能获取到,而readFile
读取不到呢?
因而查了很多资料,看到了一些关于require
引入模块的机制,从中学到了很多,也明白了为何是这样。
咱们先了解一下require()
的基本用法:
下面的内容来自require() 源码解读,由阮一峰翻译自《Node使用手册》。
咱们从第(2)小条的a部分能够看出:
(2)若是 X 以 "./" 或者 "/" 或者 "../" 开头 a. 根据 X 所在的父模块,肯定 X 的绝对路径。 b. 将 X 当成文件,依次查找下面文件,只要其中有一个存在,就返回该文件,再也不继续执行。
const test = require('./1.findLargest.js')
按照上面规则翻译一遍就是:
根据1.findLargest.js
所在的父模块,肯定1.findLargest.js
的绝对路径为/Users/jawil/Desktop/nodejs/demo/ES6-lottery/syntax/nodejs
,关于其中的寻找细节这里不作探讨。
先把1.findLargest.js
当成文件,依次查找当前目录下的1.findLargest.js
,找到了,就返回该文件,再也不继续执行。
根据require
的基本规则,对于上面出现的情形也就不足为奇了,更多require
的机制和源码解读,请移步:
require() 源码解读。
那么关于 ./
正确的结论是:
在 require()
中使用是跟 __dirname
的效果相同,不会由于启动脚本的目录不同而改变,在其余状况下跟 process.cwd()
效果相同,是相对于启动脚本所在目录的路径。
__dirname: 得到当前执行文件所在目录的完整目录名
__filename: 得到当前执行文件的带有完整绝对路径的文件名
process.cwd():得到当前执行node命令时候的文件夹目录名
./: 不使用require时候,./与process.cwd()同样,使用require时候,与__dirname同样
只有在 require()
时才使用相对路径(./, ../)
的写法,其余地方一概使用绝对路径,以下:
// 当前目录下 path.dirname(__filename) + '/path.js'; // 相邻目录下 path.resolve(__dirname, '../regx/regx.js');
最后看看改过以后的结果,不会报错找不到文件了,无论在哪里执行这个脚本文件,都不会出错了,防止之后踩坑。