09月03, 2017

node中多种读取文件方式的异同

一个小坑

最近给项目添加pm2的时候,踩了一个坑。文件的目录结构如下:

/project
  /app
    start.js
    data.json
  pm2.json

start.js中,有如下操作:

fs.readFile('./data.json', function (err, buffer) {
  if (err) {
    return console.log('error: ', err);
  }
  console.log('OK');
});

之前启动start.js都是直接在/project/app/下执行node start.js,程序可以正常运行。但是在使用pm2时,我的配置文件如下:

{
  "apps": [{
    "name": "project",
    "script": "app/start.js",
    ...
  }]
}

当使用pm2 start pm2.json时,程序就回报错中断 :

error:  { Error: ENOENT: no such file or directory, open './data.json'
    at Error (native)
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: './data.json' }

最后修改pm2.json内容为:

{
  "apps": [{
    "name": "project",
    "script": "start.js",
    "cwd": "/project/app"
    ...
  }]
}

再次启动,程序可以正常运行。

或者还原pm2.json,只修改start.js中内容为:

fs.readFile(path.resolve(__dirname, './data.json'), function (err, buffer) {
  if (err) {
    return console.log('error: ', err);
  }
  console.log('OK');
});

程序也可以正常运行。

背后的故事

我们先来数一数node中,获取文件路径的几种方法__dirname__filenameprocess.cwd()./

我们创建一个新文件test.js,同样放在/project/app/目录中,该文件内容如下:

var path = require('path');

console.log('__dirname = ', __dirname);
console.log('__filename = ', __filename);
console.log('process.cwd() = ', process.cwd());
console.log('./ = ', path.resolve('./'));

首先,我们在/project/app文件夹下运行node test.js,输出内容如下:

__dirname =  /project/app
__filename =  /project/app/test.js
process.cwd() =  /project/app
./ =  /project/app

接着,我们再在/project文件夹下运行node app/test.js,结果如下:

__dirname =  /project/app
__filename =  /project/app/test.js
process.cwd() =  /project
./ =  /project

从上面的内容中我们可以看到,__dirname返回的永远都是运行的js文件所在目录的绝对路径,__filename返回的永远都是运行的js文件的绝对路径。而process.cwd()path.resolve('./')返回的都是node指令运行时所在目录的绝对路径。

这也就解释了上面所说问题的两种解决方案为什么都可以。

补充

我们在node中经常会用require('./xx')的方式来引入一个模块,这时无论在哪个目录下运行node命令,程序都可以正常读取到模块内容,这是因为require读取文件的流程,和我们上面所说的不一样,具体可以直接查看node官方文档中对require读取模块流程的详细说明。

本文链接:https://www.imliutao.com/post/node-filepath.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。