NodeJS 之 fs 模块(路径动态拼接问题)
参考描述问题描述准备工作content.txtmain.js复现前奏惊雷再探分析解决__dirnamepath 模块path.join()解决参考
描述
问题
描述
在使用 NodeJS 的 fs 模块处理文件时,你可能经常在路径中使用./或../来指明某个文件(夹)位于当前工作目录或其父目录中。使用相对路径指定文件的位置相比使用绝对路径来指定文件的位置要方便许多,但这样可能会导致意外事故的发生。
准备工作
content.txt
这是content.txt文件中的内容,我们稍后将通过 fs 模块读取该文件。
隐约雷鸣,阴霾天空。但盼风雨来,能留你在此。
隐约雷鸣,阴霾天空。即使无天雨,我亦留此地。
main.js
这是main.js文件中的内容,稍后我将通过 NodeJS 执行该文件以读取content.txt文件中的内容。
const fs = require('fs');// 尝试读取当前工作目录下的 content.txt 文件fs.readFile('./content.txt', 'utf-8', (err, data) => {if(err){console.log('【文件读取失败】')}else{console.log(data)}})
注:
content.txt与main.js文件位于同一目录之下。content.txt与main.js文件所在的路径分别为: C:\Users\36683\Template\content.txtC:\Users\36683\Template\main.js
复现
前奏
进入main.js所在的目录下后,在终端中输入如下命令以执行main.js文件中的内容。
node main.js
终端将输出如下内容:
隐约雷鸣,阴霾天空。但盼风雨来,能留你在此。
隐约雷鸣,阴霾天空。即使无天雨,我亦留此地。
惊雷
首先,让我们使用如下命令进入当前目录的父级目录中:
cd ..
执行如下命令以读取content.txt文件中的内容:
node Template/main.js
打印结果为:
【文件读取失败】
再探
由于我们使用 fs 模块捕获了错误,所以错误信息并没有打印出来。我们需要获得错误信息以对该问题产生的原因有更准确的了解。
将main.js文件中的内容修改为:
const fs = require('fs');// 尝试读取当前工作目录下的 content.txt 文件fs.readFile('./content.txt', 'utf-8', (err, data) => {if(err){console.log('【文件读取失败】');// 打印错误信息console.log(err.message);}else{console.log(data)}})
再次执行如下命令以读取content.txt文件中的内容:
node Template/main.js
打印结果:
【文件读取失败】
ENOENT: no such file or directory, open ‘C:\Users\36683\content.txt’
分析
content.txt文件的路径应该为:
C:\Users\36683\Template\content.txt
可再错误信息中得到的却是:
C:\Users\36683\content.txt
这是因为,NodeJS 在执行 JavaScript 文件时,会将其中的相对路径与执行命令时所在的工作目录进行拼接。
解决
前面你所认识到的问题便是路径拼接问题,该问题的解决方法有两种:
使用绝对路径而非相对路径指定计算机中的文件。通过 NodeJS 来获取被 NodeJS 执行的文件所在的文件夹的路径与目标文件(将要读取的文件)的相对路径进行拼接得到目标文件的绝对路径。
第一种解决方式相信各位都懂;第二种方式更具灵活性,不用担心将项目文件(包含content.txt及main.js文件的文件夹)转移到其他计算机后无法正常使用。
__dirname
__dirname是 NodeJS 中内置的一个变量,保存着该文件所在的目录的路径。
首先,让我们在终端中使用如下命令切换工作目录至main.js文件所在的文件夹中。
cd Template
进来该目录后,将main.js修改为如下内容。
const fs = require('fs');// 尝试读取当前工作目录下的 content.txt 文件fs.readFile('./content.txt', 'utf-8', (err, data) => {if(err){console.log('【文件读取失败】');console.log(err.message);}else{console.log(__dirname)}})
执行结果为:
C:\Users\36683\Template
path 模块
在使用__dirname获取到被 NodeJS 执行的文件所在的文件夹的路径后,我们需要将其与目标文件(将要读取的文件)的相对路径进行拼接。
路径的拼接尽量不要使用像拼接字符串那样使用+号进行拼接,更好的方法是使用 NodeJS 内置的path模块中path.join()来进行拼接。
path.join()
Windows使用的文件分割符为\,当然你也可以使用/,但这并不规范;而在Linux及MacOS中,操作系统使用的文件分割符均为/,在这些操作系统中,\将被理解为转义字符的前缀。
为了提高程序在不同平台中的兼容性,我们需要正确的使用文件分隔符,而path.join()很好的解决了这个问题。
path.join() 方法使用特定于平台的分隔符作为定界符将所有给定的 path 片段连接在一起,然后规范化生成的路径。
path.join([...paths])
举个栗子:
const path = require('path');result = path.join('c', 'TwoMoons', 'RedHeart');console.log(result)
打印结果:
C:\Users\36683\Template
注:
由打印结果可以发现,path.join()将我们传递给其的c转换为C。
解决
将main.js修改为如下内容后,切换工作目录为当前工作目录的父级目录。
const fs = require('fs');const path = require('path');const target = path.join(__dirname, 'content.txt')// 尝试读取当前工作目录下的 content.txt 文件fs.readFile(target, 'utf-8', (err, data) => {if(err){console.log('【文件读取失败】');console.log(err.message);}else{console.log(data)}})
执行结果:
隐约雷鸣,阴霾天空。但盼风雨来,能留你在此。
隐约雷鸣,阴霾天空。即使无天雨,我亦留此地。
至此,路径动态拼接问题已成功解决。