第6章 文件操作

    • 理解同步和异步概念
    • 掌握基本的文件读写
    • 掌握 path 模块基本使用
    • 理解文件操作的相对路径

    fs模块对文件的几乎所有操作都有同步和异步两种形式,例如:readFile()readFileSync()

    同步与异步文件系统调用的区别

    • 同步调用立即执行,会阻塞后续代码继续执行,如果想要捕获异常需要使用 try-catch
    • 异步调用不会阻塞后续代码继续执行,需要回调函数作为额外的参数,通常包含一个错误作为回调函数的第一个参数
    • 异步调用通过判断第一个err对象来处理异常
    • 异步调用结果往往通过回调函数来进行获取

    Node 只在文件IO操作中,提供了同步调用和异步调用两种形式,两者可以结合使用,
    但是推荐能使用异步调用解决问题的情况下,少用同步调用。

    对于文件操作,Node 几乎为所有的文件操作 API 提供了同步操作和异步操作两种方式。

    • 同步会阻塞程序的执行,效率低(知道就行)
    • 异步相当于多找了一个人帮你干活,效率高
    • 所以建议:尽量使用异步

    常用 API

    监视文件/目录

    path 模块

    参考文档:

    path 是 Node 本身提供的一个核心模块,专门用来处理路径。

    使用它的第一步就是先加载:

    1. path.basename('/foo/bar/baz/asdf/quux.html');
    2. // Returns: 'quux.html'
    3. path.basename('/foo/bar/baz/asdf/quux.html', '.html');
    4. // Returns: 'quux'

    path.dirname

    获取一个路径的目录部分

    1. // Returns: '/foo/bar/baz/asdf'

    path.extname

    1. path.extname('index.html');
    2. // Returns: '.html'
    3. path.extname('index.coffee.md');
    4. // Returns: '.md'
    5. path.extname('index.');
    6. // Returns: '.'
    7. path.extname('index');
    8. // Returns: ''
    9. path.extname('.index');
    10. // Returns: ''

    path.parse

    将一个路径转换为一个对象,得到路径的各个组成部分

    path.format(pathObject)

    将具有特定属性的对象转换为一个路径

    1. // If `dir`, `root` and `base` are provided,
    2. // `${dir}${path.sep}${base}`
    3. // will be returned. `root` is ignored.
    4. path.format({
    5. root: '/ignored',
    6. dir: '/home/user/dir',
    7. base: 'file.txt'
    8. });
    9. // Returns: '/home/user/dir/file.txt'
    10. // If only `root` is provided or `dir` is equal to `root` then the
    11. // platform separator will not be included. `ext` will be ignored.
    12. path.format({
    13. root: '/',
    14. base: 'file.txt',
    15. ext: 'ignored'
    16. });
    17. // Returns: '/file.txt'
    18. // `name` + `ext` will be used if `base` is not specified.
    19. path.format({
    20. root: '/',
    21. name: 'file',
    22. ext: '.txt'
    23. });
    24. // Returns: '/file.txt'

    path.join

    将多个路径拼接为一个

    1. path.join('/foo', 'bar', 'baz/asdf', 'quux', '..');
    2. // Returns: '/foo/bar/baz/asdf'
    3. // throws 'TypeError: Path must be a string. Received {}'

    Unix:

    1. path.isAbsolute('/foo/bar'); // true
    2. path.isAbsolute('/baz/..'); // true
    3. path.isAbsolute('qux/'); // false
    4. path.isAbsolute('.'); // false

    Windows:

    path.normalize(path)

    1. path.normalize('/foo/bar//baz/asdf/quux/..');
    2. // Returns: '/foo/bar/baz/asdf'
    3. path.normalize('C:\\temp\\\\foo\\bar\\..\\');
    4. // Returns: 'C:\\temp\\foo\\'

    path.resolve([…paths])

    类似于 path.join() ,也是用来路径拼接

    1. path.resolve('/foo/bar', './baz');
    2. // Returns: '/foo/bar/baz'
    3. path.resolve('/foo/bar', '/tmp/file/');
    4. // Returns: '/tmp/file'
    5. // if the current working directory is /home/myself/node,
    6. // this returns '/home/myself/node/wwwroot/static_files/gif/image.gif'

    建议:以后操作文件使用相对路径都使用 path.join() 方法结合 __dirname 来避免问题。

    路径分类

    和大多数路径规则一样,在 Node 中的路径规则同样遵守以下方式:

    • 绝对路径
      • / 开头的路径,例如 /a/b/c
        • 在 Linux 中就是操作系统的根路径
        • 在 Windows 中是当前 JavaScript 脚本所属磁盘根路径
      • c:/ 开头的盘符路径,例如 c:/a/b/c
    • 相对路径
      • ./ 开头的相对路径,例如 ./a/b/c
        • 在这里 ./ 可以省略,a/b/c 等价于 ./a/b/c
        • 注意,. 不能省略,否则 /a/b/c 就是一个绝对路径
      • ../ 开头的相对路径,例如 ../a/b/c
    1. // 相对于当前路径
    2. fs.readFile('./README.md')
    3. // 相对当前路径,可以省略 ./
    4. // 注意:加载模块中的标识路径不能省略 ./
    5. fs.readFile('README.md')
    6. // 绝对路径
    7. fs.readFile('c:/README.md')
    8. // 绝对路径,当前 js 脚本所处磁盘根目录
    9. fs.readFile('/README.md')

    相对路径操作的问题

    相对路径到底相对于谁?

    __dirname__filename

    在每个模块中,除了 requireexports 等模块成员之外,还有两个特殊的成员:

    • __dirname 动态获取 当前文件模块所属目录的绝对路径
    • __filename 动态获取 当前文件的绝对路径

    把相对路径转换为动态的绝对路径

    使用 path.join() 方法解决拼接的问题

    路径使用整理

    总结

    • 相对路径永远是相对于执行 node 命令所处的路径

    • 绝对路径永远是绝对路径, 永远不会受影响

    注意:模块标识路径还是相对于文件模块本身,还这里的文件操作中的相对路径规则没有关系。