關(guān)于Node.js的__dirname,__filename,process.cwd(),./文件路徑的一些坑

起因

原文收錄在我的 GitHub博客 (https://github.com/jawil/blog) ,喜歡的可以關(guān)注最新動(dòng)態(tài),大家一起多交流學(xué)習(xí),共同進(jìn)步,以學(xué)習(xí)者的身份寫(xiě)博客,記錄點(diǎn)滴。

最近在學(xué)習(xí)Node.js里面的fs模塊,遇到了一個(gè)比較詭異的現(xiàn)象,踩到了坑,就是讀取當(dāng)前目錄下的一個(gè)文件,死活讀取不到,由于之前對(duì)于Node.js里面的path模塊也不太熟悉,也沒(méi)系統(tǒng)研究過(guò),所以今天就踩了這個(gè)坑,記錄踩坑的過(guò)程,防止以后踩坑和大家也踩坑。

說(shuō)一下當(dāng)時(shí)的情形:


QQ20170510-181437

我納悶的很半天,我明明就是讀取當(dāng)前目錄下的1.findLargest.js,為什么提示找不到這個(gè)文件,運(yùn)行了幾遍,死活找不到1.findLargest.js這個(gè)文件。

后來(lái)才發(fā)現(xiàn)是因?yàn)檫\(yùn)行這個(gè)文件不是從當(dāng)前目錄運(yùn)行了,從圖中可以看出,當(dāng)前的目錄是/Users/jawil/Desktop/nodejs/demo/ES6-lottery/syntax/nodejs,而我運(yùn)行這個(gè)腳本的目錄是/Users/jawil/Desktop/nodejs/demo/ES6-lottery;這就是問(wèn)題的所在了。不過(guò)為什么運(yùn)行腳本的位置也會(huì)影響這個(gè)路徑呢,且往下看。

探索

計(jì)算機(jī)不會(huì)欺騙人,一切按照規(guī)則執(zhí)行,說(shuō)找不到這個(gè)文件,那肯定就是真的找不到,至于為什么找不到,那就是因?yàn)槲覀兝斫庥衅睿易畛趵斫獾?./'是當(dāng)前執(zhí)行js文件所在的文件夾的絕對(duì)路徑,然后Node.js的理解卻不是這樣的,我們慢慢往下看。

Node.js中的文件路徑大概有 __dirname, __filename, process.cwd(), ./ 或者 ../,前三個(gè)都是絕對(duì)路徑,為了便于比較,./../ 我們通過(guò) path.resolve('./')來(lái)轉(zhuǎn)換為絕對(duì)路徑。

簡(jiǎn)單說(shuō)一下這幾個(gè)路徑的意思,:

__dirname:    獲得當(dāng)前執(zhí)行文件所在目錄的完整目錄名
__filename:   獲得當(dāng)前執(zhí)行文件的帶有完整絕對(duì)路徑的文件名
process.cwd():獲得當(dāng)前執(zhí)行node命令時(shí)候的文件夾目錄名 
./:           文件所在目錄

先看一看我電腦當(dāng)前的目錄結(jié)構(gòu):

syntax/
    -nodejs/
        -1.findLargest.js
        -2.path.js
        -3.fs.js
    -regs
        -regx.js
        -test.txt

在 path.js 里面我們寫(xiě)這些代碼,看看輸出是什么:

const path = require('path')
console.log('__dirname:', __dirname)
console.log('__filename:', __filename)
console.log('process.cwd():', process.cwd())
console.log('./:', path.resolve('./'))

在當(dāng)前目錄下也就是nodejs目錄運(yùn)行 node path.js,我們看看輸出結(jié)果:

__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
QQ20170510-183712

然后在 項(xiàng)目根目錄ES6-lottery 目錄下運(yùn)行 node syntax/nodejs/2.path.js,我們?cè)賮?lái)看看輸出結(jié)果:

__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
QQ20170510-184943

答案顯而易見(jiàn)?我們可以通過(guò)上面的例子對(duì)比,暫時(shí)得出表面的結(jié)論:

  • __dirname: 總是返回被執(zhí)行的 js 所在文件夾的絕對(duì)路徑
  • __filename: 總是返回被執(zhí)行的 js 的絕對(duì)路徑
  • process.cwd(): 總是返回運(yùn)行 node 命令時(shí)所在的文件夾的絕對(duì)路徑
  • ./: 跟 process.cwd() 一樣,返回 node 命令時(shí)所在的文件夾的絕對(duì)路徑

但是,我們?cè)賮?lái)看看這個(gè)例子,我們?cè)谏厦娴睦蛹訋拙浯a,然后:

我們?cè)?code>1.findLargest.js先加這句代碼

exports.A = 1;

再來(lái)在剛才報(bào)錯(cuò)的3.fs.js里面加這兩句代碼看看:

const test = require('./1.findLargest.js');

console.log(test)

運(yùn)行node syntax/nodejs/3.fs.js,最后看看結(jié)果:

QQ20170510-185549

再次疑惑

為什么都是讀取./1.findLargest.js文件,一樣的路徑,為什么require能獲取到,而readFile讀取不到呢?

于是查了不少資料,看到了一些關(guān)于require引入模塊的機(jī)制,從中學(xué)到了不少,也明白了為什么是這樣。

我們先了解一下require() 的基本用法:

下面的內(nèi)容來(lái)自require() 源碼解讀,由阮一峰翻譯自《Node使用手冊(cè)》。

QQ20170510-190528

我們從第(2)小條的a部分可以看出:

(2)如果 X 以 "./" 或者 "/" 或者 "../" 開(kāi)頭 
  a. 根據(jù) X 所在的父模塊,確定 X 的絕對(duì)路徑。
  b. 將 X 當(dāng)成文件,依次查找下面文件,只要其中有一個(gè)存在,就返回該文件,不再繼續(xù)執(zhí)行。

const test = require('./1.findLargest.js')按照上面規(guī)則翻譯一遍就是:

  1. 根據(jù)1.findLargest.js所在的父模塊,確定1.findLargest.js的絕對(duì)路徑為/Users/jawil/Desktop/nodejs/demo/ES6-lottery/syntax/nodejs,關(guān)于其中的尋找細(xì)節(jié)這里不做探討。

  2. 先把1.findLargest.js當(dāng)成文件,依次查找當(dāng)前目錄下的1.findLargest.js,找到了,就返回該文件,不再繼續(xù)執(zhí)行。

根據(jù)require的基本規(guī)則,對(duì)于上面出現(xiàn)的情形也就不足為奇了,更多require的機(jī)制和源碼解讀,請(qǐng)移步:
require() 源碼解讀。

那么關(guān)于 ./ 正確的結(jié)論是:
require() 中使用是跟 __dirname 的效果相同,不會(huì)因?yàn)閱?dòng)腳本的目錄不一樣而改變,在其他情況下跟 process.cwd() 效果相同,是相對(duì)于啟動(dòng)腳本所在目錄的路徑。

總結(jié):

  • __dirname: 獲得當(dāng)前執(zhí)行文件所在目錄的完整目錄名
  • __filename: 獲得當(dāng)前執(zhí)行文件的帶有完整絕對(duì)路徑的文件名
  • process.cwd():獲得當(dāng)前執(zhí)行node命令時(shí)候的文件夾目錄名
  • ./: 不使用require時(shí)候,./與process.cwd()一樣,使用require時(shí)候,與__dirname一樣

只有在 require() 時(shí)才使用相對(duì)路徑(./, ../)的寫(xiě)法,其他地方一律使用絕對(duì)路徑,如下:


// 當(dāng)前目錄下
 path.dirname(__filename) + '/path.js'; 
// 相鄰目錄下
 path.resolve(__dirname, '../regx/regx.js');

最后看看改過(guò)之后的結(jié)果,不會(huì)報(bào)錯(cuò)找不到文件了,不管在哪里執(zhí)行這個(gè)腳本文件,都不會(huì)出錯(cuò)了,防止以后踩坑。

QQ20170510-193604
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 個(gè)人入門(mén)學(xué)習(xí)用筆記、不過(guò)多作為參考依據(jù)。如有錯(cuò)誤歡迎斧正 目錄 簡(jiǎn)書(shū)好像不支持錨點(diǎn)、復(fù)制搜索(反正也是寫(xiě)給我自己看...
    kirito_song閱讀 2,637評(píng)論 1 37
  • Node.js是目前非?;馃岬募夹g(shù),但是它的誕生經(jīng)歷卻很奇特。 眾所周知,在Netscape設(shè)計(jì)出JavaScri...
    w_zhuan閱讀 3,720評(píng)論 2 41
  • 1 Node.js模塊的實(shí)現(xiàn)# 之前在網(wǎng)上查閱了許多介紹Node.js的文章,可惜對(duì)于Node.js的模塊機(jī)制大都...
    七寸知架構(gòu)閱讀 2,151評(píng)論 1 50
  • 1 Node.js模塊的實(shí)現(xiàn) 之前在網(wǎng)上查閱了許多介紹Node.js的文章,可惜對(duì)于Node.js的模塊機(jī)制大都著...
    zlx_2017閱讀 1,478評(píng)論 0 1
  • 這是一個(gè)發(fā)生在我身邊的真實(shí)案例,已經(jīng)過(guò)去半月有余,至今想來(lái)仍覺(jué)得汗毛直豎,把孩子養(yǎng)大太不容易了,他們這一生遇到的各...
    職場(chǎng)媽媽閱讀 401評(píng)論 0 2

友情鏈接更多精彩內(nèi)容