08月19, 2016

node路径问题&path模块处理文件路径

常见路径:

node中的文件路径主要有__dirname__filenameprocess.cwd()./../,前三个都是绝对路径,为了便于比较,./../我们通过path.resolve('./')来转换为绝对路径。

举个栗子:

假如我们有这样一个目录结构:

app/
    -lib/
        -common.js
    -model/
        -task.js
        -test.js

在test.js里编写如下的代码:

var path = require("path");
console.log(__dirname);
console.log(__filename);
console.log(process.cwd());
console.log(path.resolve("./"));

在model目录下运行node task.js得到的输出是:

/home/ivan/app/model
/home/ivan/app/model/task.js
/home/ivan/app/model
/home/ivan/app/model

然后在app目录下运行node model/task.js,得到输出结果:

/home/ivan/app/model
/home/ivan/app/model/task.js
/home/ivan/app
/home/ivan/app

依上,我们是否可以得到这样的一个结论:

  • __dirname总是返回被执行的js所在文件夹的绝对路径。
  • __filename总是返回被执行js文件的绝对路径。
  • process.cwd()总是返回运行node命令所在的文件夹的绝对路径。
  • ./process.cwd()一样一样的。

但是经常见到 require('../lib/common')里一直都是各种相对路径写,也没见什么报错呀, 再举个栗子,还是上面的结构,model/task.js里的代码改成:

var fs = require("fs");
var common = require("../lib/common");

fs.readFile("../lib/common.js", function (err, data) {
    if (err) return console.log(err);
    console.log(data);
});

在model目录下运行node task.js,一切OK,都没有报错。然后在app目录下运行node model/task.js,然后很果断的就报错了:

{ [Error: ENOENT: no such file or directory, open "../lib/common.js"]
  errno: -2,
  code: "ENOENT",
  syscall: "open",
  path: "../lib/common.js" }

所以,问题来了。按照前面得到的结论,./process.cwd()一样一样的。那么在model目录下执行的时候,../lib/common.js会被转变成/home/ivan/app/lib/common.js,在app目录下执行的时候,../lib/common.js会被转变成/home/ivan/lib/common.js,这个路径是不存在的,但是从运行结果来看,require('../lib/common')是OK的,只是readFile时报错了。

那么关于./正确的结论出来了: 在require()中使用的是跟__dirname的效果相同,不会因为启动脚本的目录不一样而改变,在其他情况下跟process.cwd()效果相同,是相对于启动脚本所在目录的路径。

总结

所以事实证明前端得到的结论中1,2,3是OK的,最后一个不准确。

只有在require()时才使用相对路径的写法,其他地方一律使用绝对路径,如下:

var path= require(“path”);
//当前目录下
path.dirname(__filename)+"/test.js";
//相邻目录下
path.resolve(__dirname, "../lib/common.js");

扩展

Node.js使用path模块处理文件路径

  • path.normalize(p) 文件路径处理 path模块中的normalize()方法用来规范化路径字符串。可用于处理路径中的"//"、".."、"."等字符

      var path = require("path");
      path.normalize("/foo/bar//baz/asdf/..");
      // 处理后
      "/foo/bar/baz/asdf"
    
  • path.join([path1][, path2][, ...]) 连接路径

    path.join()方法可以连接任意多个路径字符串。要连接的多个路径可做为参数传入。path.join()方法在接边路径的同时也会对路径进行规范化。例如:

      var path = require("path");
      //合法的字符串连接
      path.join("/foo", "bar", "baz/asdf", "..")
      // 连接后
      "/foo/bar/baz/asdf"
    
      //不合法的字符串将抛出异常
      path.join("foo", {}, "bar")
      // 抛出的异常
      TypeError: Arguments to path.join must be strings"
    
  • path.resolve([from ...], to) 路径解析 path.resolve()方法可以将多个路径解析为一个规范化的绝对路径。其处理方式类似于对这些路径逐一进行cd操作,与cd操作不同的是,这引起路径可以是文件,并且可不必实际存在(resolve()方法不会利用底层的文件系统判断路径是否存在,而只是进行路径字符串操作)。例如:

      path.resolve("foo/bar", "/tmp/file/", "..", "a/../subfile")
    

    其处理方式类型于

      cd foo/bar
      cd /tmp/file/
      cd ..
      cd a/../subfile
      pwd
    

    如果解析的不是绝对路径,path.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/ivan/test,则输出结果为
      "/home/ivan/test/wwwroot/static_files/gif/image.gif"
    
  • path.relative(from, to) 查找两个绝对路径的相对关系 path.relative()方法可以找出一个绝对路径到另一个绝对路径的相对关系。例如:

      var path = require("path");
      path.relative("/Users/ivan/test/app/demo", "/Users/ivan/test/lib");
      // 结果
      "../../lib"
    
  • path.dirname(p) path.basename(p[, ext]) path.extname(p) 提取路径的组成部分

    path.dirname()方法可以提取出一个文件路径中的目录的部分。

    path.basename()方法可以提取出一个文件路径中的文件的部分。

    path.extname()方法可以提取文件的扩展名。例如:

var path = require("path");
path.dirname("/Users/ivan/demo/path.js")
// 结果
"/Users/ivan/demo"

path.basename("/Users/ivan/demo/path.js")
// 结果
"path.js"

path.extname("/Users/ivan/demo/path.js")
// 结果
".js"

path.basename()方法还可以指定第二个参数:文件的扩展名,指定后可以提取文件名。指定扩展名不合法时将返回文件全名。例如:

var path = require("path");

path.basename("/Users/ivan/demo/path.js", ".js")
// 结果
"path"

path.basename("/Users/ivan/demo/path.js", ".html")
// 结果
"path.js"

在早期的Node.js版本中path模块还有个path.exists()方法,用于判断文件是否存在,但已被fs模块中的fs.exists()代替。

以上。

本文链接:http://westpsk.com/post/node-path.html

-- EOF --

Comments