【Node.js】Node.js中path.resolve与path.join的区别与作用详解

 

前言:

1、path 模块,node自带模块,用于处理文件和目录的路径的实用工具,使用前需先引入模块 const path = require('path')

2、当前文件路径 和 当前工作目录,例如:1、 E:\vue2-starter>node ../path.js(E:\vue2-starter表示工作目录,E:\path.js则是文件路径,E:\>node path.js(E:\表示工作目录路径,E:\path.js是文件路径)

3、node自带的全局变量,__dirname (文件目录)   __filename(文件路径

// index.js 位于E:\, 运行在E:\下运行node index(与在E:\vue2-starter运行node ../index并无不同)

console.log(__dirname) // e:\,文件目录名 console.log(__filename) // e:\index.js ,文件路径 //

4、绝对路径, 可以用path.isAbsolute(path)进行判断

//绝对路径: ‘/app’(在windows下会在前面加上盘符)、‘C:\app\state’(windows)’

//非绝对路径:‘app/state’、 ‘.’

5、path的处理方式

path.join():用于链接路径,并且会自动转换当前系统路径的分隔符"/"或"\",Unix系统是"/",Windows系统是"\"

path.resolve():也是用于链接路径,但却和path.join()方法却很多不同,而且path.resolve()方法本身就自带一个to的绝对路径参数,也会自动转换分隔符,在某些场景用起来也方便很多;

__dirname:是node的一个全局变量,获得当前文件所在目录的完整目录名,搭配path一起使用;

 

一、关于 path.resolve() 的使用

语法path.resolve([from ...], to)

用法:将 to 参数解析为绝对路径,给定的路径的序列是从右往左被处理的,后面每个 path 被依次解析,直到构造完成一个绝对路径。 例如,给定的路径片段的序列为:/foo、/bar、baz,则调用 path.resolve('/foo', '/bar', 'baz') 会返回 /bar/baz。

简要理解

1、给定的路径序列会从右到左进行处理,后面的每个 path 会被追加到前面,直到构造出绝对路径

2、如果在处理完所有给定的 path 片段之后还未生成绝对路径,则会在前面添加当前工作目录

3、生成的路径会被规范化,并且尾部的斜杠会被删除(除非路径被解析为根目录)。

4、如果没有传入 path 片段,则 path.resolve() 会返回当前工作目录的绝对路径。

console.log(path.resolve('/index')) // 盘符:\index
console.log(path.resolve('index')) // 当前工作目录的绝对路径/index
console.log(path.resolve('/app', 'index/')) // 盘符:\app\index
console.log(path.reolve())// 当前工作目录的绝对路径

 

 

案例一:

演示当"path"路径为空时,得到结果是当前文件所在的绝对路径,类似 __dirname

复制代码
// 引入path模块
const path = require('path');
 
// 此处直接打印
console.log(path.resolve());
console.log(path.resolve(''));
console.log(path.resolve(__dirname);
// 输出:E:\Berlin-Case\path
// 输出:E:\Berlin-Case\path
// 输出:E:\Berlin-Case\path
复制代码

 

案例二:

演示字符以 ./ 开头或者没有字符时,得到的结果是加不加 ./ 都不影响路径的拼接;

复制代码
// 引入path模块
const path = require('path');
 
// 此处直接打印
console.log(path.resolve());
console.log(path.resolve('a'));
console.log(path.resolve('a','b'));
console.log(path.resolve('c','b','a'));
console.log(path.resolve('./a'));
console.log(path.resolve('a','./b'));
console.log(path.resolve('./c','b','./a'));
// 输出:E:\Berlin-Case\path
// 输出:E:\Berlin-Case\path\a
// 输出:E:\Berlin-Case\path\a\b
// 输出:E:\Berlin-Case\path\c\b\a
// 输出:E:\Berlin-Case\path\a
// 输出:E:\Berlin-Case\path\a\b
// 输出:E:\Berlin-Case\path\c\b\a
复制代码

案例三: 

演示字符以 / 开头,path.resolve()的特点之一就是碰到"/"斜杆则会直接跳转到E盘的根路径(在哪个盘运行就是哪个盘),这里跟在终端输出cd /是一样的原理,也会跳转到E盘的根路径;

复制代码
// 引入path模块
const path = require('path');
 
// 此处直接打印
console.log(path.resolve());
console.log(path.resolve('/a'));
console.log(path.resolve('/a','b','c'));
console.log(path.resolve('a','/b','c'));
console.log(path.resolve('c','b','/a'));
// 输出:E:\Berlin-Case\path
// 输出:E:\a
// 输出:E:\a\b\c
// 输出:E:\b\c
// 输出:E:\a
复制代码

 

案例四:

演示字符以../开头,也就是上一层的意思,path.resolve()会把下个要拼接的"path"路径给覆盖掉;

复制代码
// 引入path模块
const path = require('path');
 
// 此处直接打印
console.log(path.resolve());
console.log(path.resolve('../'));
console.log(path.resolve('../a'));
console.log(path.resolve('../a','b'));
console.log(path.resolve('a','../b'));
console.log(path.resolve('c','b','../a'));
console.log(path.resolve('../c','b','a'));
// 输出:E:\Berlin-Case\path
// 输出:E:\Berlin-Case\
// 输出:E:\Berlin-Case\a
// 输出:E:\Berlin-Case\a\b
// 输出:E:\Berlin-Case\path\b
// 输出:E:\Berlin-Case\path\c\a
// 输出:E:\Berlin-Case\c\b\a
复制代码

 

 案例五:

演示path.resolve()搭配__dirname变量

复制代码
// 引入path模块
const path = require('path');
 
// 此处直接打印
console.log(path.resolve(__dirname,'a'));
console.log(path.resolve('a','b',__dirname));
console.log(path.resolve(__dirname,'./a','b'));
console.log(path.resolve(__dirname,'/a','b'));
console.log(path.resolve(__dirname,'../a','b'));
console.log(path.resolve(__dirname,'a','../b'));
console.log(path.resolve('a','/b',__dirname));
 
// 输出:E:\Berlin-Case\path\a
// 输出:E:\Berlin-Case\path
// 输出:E:\Berlin-Case\path\a\b
// 输出:E:\a\b
// 输出:E:\Berlin-Case\a\b
// 输出:E:\Berlin-Case\path\b
// 输出:E:\Berlin-Case\path
复制代码

从案例五例子可以看出,

一、__dirname变量需放在第一个,否则会覆盖在它之前的'path'路径,包括斜杠' / ',

二、__dirname之后也不能出现' / ',不然也覆盖之前的路径;

 

总结:
path.resolve("./path")的特性有以下几点:

从右往左读取"path"路径,并开始拼接,本身就自带绝对路径参数 "to" ;
当"path"路径为空时,则会直接获取当前文件所在的绝对路径;
当遇到字符以 ./ 开头或者没有字符,则正常拼接,所以可省略不加字符;
当遇到字符以 / 开头,则不会拼接到前面的路径并以自身所在盘为根路径加以拼接;
当遇到字符以 ../ 开头,则会将下一个要拼接"path"路径给覆盖,然后继续往左拼接;
搭配__dirname时,需将放置第一位,且与 ' / ' 有互相覆盖的冲突;

二、关于 path.join() 的使用

语法:path.join([path1][, path2][, ...])

用法:用于连接路径

简要理解:1、path.join() 方法会将所有给定的 path 片段连接到一起(使用平台特定的分隔符作为定界符),然后规范化生成的路径。

path.join('/目录1', '目录2', '目录3/目录4', '目录5', '..');
// 返回: '/目录1/目录2/目录3/目录4'(windows下:盘符:\录1\目录2\目录3\目录4)

 

案例一:

演示当"path"路径为无或空时,得到的结果是" . ",只有传入__dirname的时候,才能得到绝对路径

复制代码
// 引入path模块
const path = require('path');
 
// 此处直接打印
console.log(path.join());
console.log(path.join(''));
console.log(path.join(__dirname));
// 输出:.
// 输出:.
// 输出:E:\Berlin-Case\path
复制代码

案例二:

演示字符以 ./ 开头或者 / 和没有字符,得到的结果是加不加都不影响路径的拼接,此时你应该发现跟path.resolve()的有所不同了,因为 join() 只会单纯的去拼接你写入的"path"路径,而不会像path.resolve()那样用cd去运作;

复制代码
// 引入path模块
const path = require('path');
 
// 此处直接打印
console.log(path.join());
console.log(path.join('a'));
console.log(path.join('a','b'));
console.log(path.join('c','b','a'));
console.log(path.join('./a'));
console.log(path.join('a','./b'));
console.log(path.join('./c','b','./a'));
console.log(path.join('/a'));
console.log(path.join('a','/b'));
console.log(path.join('/c','b','/a'));
// 输出:.
// 输出:a
// 输出:a\b
// 输出:c\b\a
// 输出:a
// 输出:a\b
// 输出:c\b\a
// 输出:\a
// 输出:a\b
// 输出:\c\b\a
复制代码

案例三:

演示以 ../ 开头的字符,此时你会发现join()不仅是单纯的去拼接路径,而且也是从右到左去拼接的,../之后还有"path"路径的话,也是会被覆盖掉;

复制代码
// 引入path模块
const path = require('path');
 
// 此处直接打印
console.log(path.join());
console.log(path.join('../'));
console.log(path.join('../a'));
console.log(path.join('../a','b'));
console.log(path.join('a','../b'));
console.log(path.join('c','b','../a'));
console.log(path.join('../c','b','a'));
 
// 输出:.
// 输出:..\
// 输出:..\a
// 输出:..\a\b
// 输出:b
// 输出:c\a
// 输出:..\c\b\a
复制代码

案例四:

演示path.join()搭配__dername变量,为什么一定要把它放在第一位?

复制代码
// 引入path模块
const path = require('path');
 
// 此处直接打印
console.log(path.join(__dirname,'a'));
console.log(path.join('a',__dirname));
 
// 输出:E:\Berlin-Case\path\a
// 输出:a\E:\Berlin-Case\path
复制代码

 

看出区别了吗?对的,没错,join会不管对错,直接把你写入的路径都拼接到一块,这也是为什么要放在第一位的原因,当然resolve()就没这种问题,接下来继续演示,与字符的搭配;

复制代码
// 引入path模块
const path = require('path');
 
// 此处直接打印
console.log(path.join(__dirname,'/a'));
console.log(path.join(__dirname,'./a'));
console.log(path.join(__dirname,'../'));
console.log(path.join(__dirname,'../a'));
console.log(path.join(__dirname,'../a','b'));
 
// 输出:E:\Berlin-Case\path\a
// 输出:E:\Berlin-Case\path\a
// 输出:E:\Berlin-Case\
// 输出:E:\Berlin-Case\a
// 输出:E:\Berlin-Case\a\b
复制代码

 

以上示例可以看出,'/' './' 这两个字符在path.join()的方法中是不起作用的,不加也是一样的效果,只有 '../ ' 才有返回上级目录的作用,所以使用path.join()时,加个__dirname,拼上你要的"path"路径即可;(不加会很麻烦哦)

 

总结:

在path.join()方法中,'/' 与 './' 一般情况下可以不用(特殊情况的拼接除外哈);
在path.join()方法中,最好与__dirname变量搭配使用;
path.join()方法也是从右到左依次被解析排列组成路径的;
path.resolve与path.join的区别
结合上面两个方法的演示后的总结,它们之间的区别如下:

path.resolve()自带to参数,也就是当前输出文件的路径,而path.join()没有;
path.resolve()遇到 ' / ' 则会跳转到根目录(E:\),path.resolve()的拼接是有盘符的;而path.join()则没效果;
path.resove()搭配__dirname变量使用时,就算__dirname在最右边,resolve()会把左边的"path"路径给覆盖掉,形成正确的路径,而path.join()正常拼接,无论对错;

 



 

 

 

 

 

问题:

在win10 系统本地正常运行的 “相对” 路径 将图片随着代码上传到bamboo上运行找不到对应的地址(linux系统和windows系统的不同导致当前的运行找不到文件)

原先的代码

When(/^On web I update profile avatar and click (.*) button$/, async (button) => {
    const avatarPath = path.join(__dirname, './../../../../testdata/img/avatar.jpg')
    await MyAccountPage.uploadProfileAvatar(avatarPath, button)
})

 

提示的错误在bamboo上 找的相对路径是linux的路径 所以当前无法正确找到对应的数据,但是在windows本地能正常运行

 

 
posted @   陈晓猛  阅读(926)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
历史上的今天:
2021-11-16 什么是跨域,为什么会有跨域问题的出现
2018-11-16 【文件系统】
点击右上角即可分享
微信分享提示

目录导航