回顧Node檔案路徑

張灝哲(Martin)發表於2019-03-03

回顧Node檔案路徑

起因

node中路徑在很多地方都有使用,基礎到不起眼。但有時候就是不起眼的東西,會在你不輕易間跳出來給你上一課。

想起來複習一下檔案路徑的起因,是因為最近整理了一下專案結構,調整了目錄。這也是基於對現代IDE的信任(都是IDE給慣的病),IDE會處理好路徑問題,所以我只管拖動,他負責善後。可是沒想到啊,我盡然忘了他不會處理path.join(__dirname, `/../logs/`)這種方式的路徑。

於是在程式碼執行了兩天後,發現怎麼project/logs的裡面的日誌停更了兩天,是拖更嗎?這不行啊,我得催催更。

這才發現logger中介軟體的目錄也變了,但是處理的路徑不對,logs也沒有拖更,只是另尋他處了。

log4js.configure({
  appenders: {
    console: {
      type: `console`
    },
    koa: {
      type: `dateFile`,
      filename: path.join(__dirname, `/../logs/`), // 問題出在我身上
      pattern: `yyyy-MM-dd.log`,
      alwaysIncludePattern: true
    }
  },
  categories: { default: { appenders: [`console`, `koa`], level: `debug` } }
});
複製程式碼

那肛肛好複習一下檔案路徑吧。

複習

概念

node中分為相對路徑絕對路徑兩種,相對路徑表示當前目錄層級相對於目標的位置,而絕對路徑表示目標當前所在的位置。

相對路徑:

  • ./ 當前目錄, ../上層目錄,…

絕對路徑

  • __dirname 被執行的 js 所在目錄的絕對路徑
  • __filename 被執行的 js 的絕對路徑
  • process.cwd() 當前 node 命令執行時所在的資料夾的絕對路徑

path路徑

  • path.join([...paths]) 使用平臺特定的分隔符把所有 path 片段連線到一起,並規範化生成的路徑

  • path.resolve([...paths]) 將路徑或路徑片段的序列處理成絕對路徑。指定的路徑序列是從右往左開始處理的,後面的 path 被依次處理,直到構造完絕對路徑。 例如,指定的路徑片段序列為:/foo、/bar、baz,則呼叫 path.resolve(`/foo`, `/bar`, `baz`) 會返回 /bar/baz

// join
path.join(`/foo`, `bar`, `baz/asdf`, `quux`, `..`);
// 返回: `/foo/bar/baz/asdf`

path.join(`foo`, {}, `bar`);
// 丟擲 `TypeError: Path must be a string. Received {}`

// resolve
path.resolve(`/foo/bar`, `./baz`);
// 返回: `/foo/bar/baz`

path.resolve(`/foo/bar`, `/tmp/file/`);
// 返回: `/tmp/file`

path.resolve(`wwwroot`, `static_files/png/`, `../gif/image.gif`);
// 如果當前工作目錄是 /home/myself/node,則返回 `/home/myself/node/wwwroot/static_files/gif/image.gif`。
複製程式碼

示例

logger.js的檔案裡寫下如下程式碼:

// 所在:/Users/simon/workspace/Inspiration/FitNoteServer/src/util/logger.js
console.log(__dirname);
console.log(process.cwd());
console.log(__filename);
console.log(`----------------------`);
console.log(path.join(__dirname, `/`));
console.log(path.join(__dirname, `../logs/`));
console.log(path.join(__dirname, `../../logs`));
console.log(`----------------------`);
console.log(path.resolve(__dirname, `/`));
console.log(path.resolve(__dirname, `../logs/`));
console.log(path.resolve(__dirname, `../../logs`));
複製程式碼

然後分別在不同目錄下啟動專案:

# workspace/Inspiration/FitNoteServer
▶ node src/index.js

/Users/simon/workspace/Inspiration/FitNoteServer/src/util
/Users/simon/workspace/Inspiration/FitNoteServer
/Users/simon/workspace/Inspiration/FitNoteServer/src/util/logger.js
----------------------
/Users/simon/workspace/Inspiration/FitNoteServer/src/util/
/Users/simon/workspace/Inspiration/FitNoteServer/src/logs/
/Users/simon/workspace/Inspiration/FitNoteServer/logs
----------------------
/
/Users/simon/workspace/Inspiration/FitNoteServer/src/logs
/Users/simon/workspace/Inspiration/FitNoteServer/logs


# Inspiration/FitNoteServer/src 
▶ node index.js 

/Users/simon/workspace/Inspiration/FitNoteServer/src/util
/Users/simon/workspace/Inspiration/FitNoteServer/src
/Users/simon/workspace/Inspiration/FitNoteServer/src/util/logger.js
----------------------
/Users/simon/workspace/Inspiration/FitNoteServer/src/util/
/Users/simon/workspace/Inspiration/FitNoteServer/src/logs/
/Users/simon/workspace/Inspiration/FitNoteServer/logs
----------------------
/
/Users/simon/workspace/Inspiration/FitNoteServer/src/logs
/Users/simon/workspace/Inspiration/FitNoteServer/logs
複製程式碼

重點

上面兩個程式碼片段可以清楚的看到 node 執行目錄不同對相對路徑的影響,相對路徑 ./process.cwd() 相同,都是當前 node 命令執行時所在的資料夾的絕對路徑。

node 中,使用 require 時可以忽略這點,你可以在 require 中使用相對路徑,但是在其他的地方都需要使用絕對路徑。因為 require 內部的路徑始終相對於你呼叫它的檔案,它與你的工作目錄無關。

總結

在專案中要格外注意相對路徑與絕對路徑,除了require()其他地方路徑都要使用絕對路徑。

而絕對路徑要注意 path.joinpath.resolve 的區別,同時注意專案啟動時 node 執行的位置。

參考

stackoverflow What is the difference between __dirname and ./ in node.js?

Node.js 文件——路徑

blog

相關文章