添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

原文链接: https://blog.risingstack.com/mastering-the-nodejs-core-modules-file-system-fs-module/

在这篇文章中,我们会看一下(Node.js的)文件系统模块,文件流和一些可选的文件模块。

想象一下这样的场景,你必须使用Node.js去完成一项任务…..

通过查 官方文档 ,Google搜索解决方案或者在npm找一个可以解决这问题的模块,这任务看起来还是挺容易完成的。

嘛,这当然是可以的,但有时候核心模块就可以轻松地帮你完成工作(而不需要去查资料)。

通过 《掌握Node.js核心模块》 系列文章,你可以学习到核心模块中一些隐藏和不为人知的特性。我们也会推荐一些拓展核心模块功能的模块,对你日常的开发有极大的帮助。

Node.js 文件 模块

文件 I/O 是由简单封装的标准 POSIX 函数提供的。 通过 require('fs') 使用该模块。 所有的方法都有异步和同步两种形式。

异步的API

1
2
3
4
5
6
7
8
9
// the async api
const fs = require('fs')

fs.unlink('/tmp/hello', (err) => {
if (err) {
return console.log(err)
}
console.log('successfully deleted /tmp/hello')
})

当你开发生产代码的时候,你应该使用异步的API,因为这不会阻止 事件循环 ,使程序更加高效。

同步的API

1
2
3
4
5
6
7
8
9
10
// the sync api
const fs = require('fs')

try {
fs.unlinkSync('/tmp/hello')
} catch (ex) {
console.log(err)
}

console.log('successfully deleted /tmp/hello');

你只应该在写demo或者小的CLI时才使用同步API。

Node.js文件流

我们很少看到程序员使用文件流。

(然而)流在Node.js中是一件强大的武器,可以使程序占用更少的内存。

在Node.js中什么是文件流?

若要处理数据,流在Node.js中是最好的。你需要理解这三个概念:

  • source - 数据来源对象(译者注:理解为水的来源),
  • pipeline - 数据流向的过程(你可以在这过滤或者更新数据。译者注:理解为水管),
  • sink - 数据最后存放的地方(译者注:理解为开了水龙头后接水的容器)。
  • 如果需要知道更多知识,可以看下Substack的 Stream Handbook .

    你可以轻松地使用流复制文件,尽管文件模块不提供相应的功能:

    1
    2
    3
    4
    5
    6
    // copy a file
    const fs = require('fs')
    const readableStream = fs.createReadStream('original.txt')
    var writableStream = fs.createWriteStream('copy.txt')

    readableStream.pipe(writableStream)

    你可能会问:为什么我要这么做,不就是一个 cp 命令吗?

    使用流去处理文件, 最大的好处是在此过程中你可以轻松地加工文件 ,下面是一个压缩文件的例子:

    1
    2
    3
    4
    5
    6
    const fs = require('fs')  
    const zlib = require('zlib')

    fs.createReadStream('original.txt.gz')
    .pipe(zlib.createGunzip())
    .pipe(fs.createWriteStream('original.txt'))

    Node.js支持

    需要从npm中得到相应模块的帮助吗?

    Learn more

    什么时候不要使用 fs.access

    使用 fs.access 的目的是为了检查指定文件或者目录的用户权限,例子如下:

    1
    2
    3
    4
    5
    6
    fs.access('/etc/passwd', fs.constants.R_OK | fs.constants.W_OK, (err) => {  
    if (err) {
    return console.error('no access')
    }
    console.log('access for read/write')
    })

    可供权限检查的常量 :

  • fs.constants.F_OK - 检查该文件在进程中是否可见,
  • fs.constants.R_OK - 检查该文件在进程中是否可读,
  • fs.constants.W_OK - 检查该文件在进程中是否可写,
  • fs.constants.X_OK - 检查该文件在进程中是否可执行。
  • 在使用 fs.open 之前,可使用 fs.access 去检查文件的可访问性,但 fs.readFile fs.writeFile 不推荐(使用 fs.access 去检查)。

    理由很简单,如果你这么做,就会引入了一个竞态条件。在查询权限和操作文件中相互竞争,另外的进程可能已经修改了那个文件。

    相反,你应该直接打开这文件并在这处理可能出现的错误。

    慎用 fs.watch

    通过使用 fs.watch ,当(被监听的)文件或者目录有变化时,你会收到通知。

    然而, fs.watch 这个API无法跨平台百分百一致,在某些系统中根本就不可用。

  • 在Linux系统中, 它使用 inotify

  • 在BSD系统中,它使用 kqueue

  • 在OS X中,文件使用 kqueue ,目录使用 FSEvents ,

  • 在SunOS中(包括Solaris和SmartOS),API是 event ports

  • 在Windows系统中, 这功能依赖于 ReadDirectoryChangesW

    注意:只有OS X和Windows系统支持递归选项,Linux不支持。

    还有,回调函数中的 fileName 参数只在Linux和Windows系统中提供,因此你应该准备好相应的回退机制以防止它是 undefined

    1
    2
    3
    4
    5
    fs.watch('some/path', (eventType, fileName) => {  
    if (!filename) {
    //filename is missing, handle it gracefully
    }
    })

    npm中有用的文件模块

    社区中维护着一些拓展了文件系统功能的模块。

    graceful-fs

    graceful-fs 是文件系统模块的替代模块,它优化了以下内容(译者注:由于存在太多专业名词,下面的不作翻译,请见谅):

  • queues up open and readdir calls, and retries them once something closes if there is an EMFILE error from too many file descriptors,

  • ignores EINVAL and EPERM errors in chown , fchown or lchown if the user isn’t root,

  • makes lchmod and lchown become noops, if not available,

  • retries reading a file if read results in EAGAIN error.

    你可以像使用文件模块一样使用它,或者都引入它们,根据需要二选一使用。

    1
    2
    3
    4
    5
    6
    7
    // use as a standalone module
    const fs = require('graceful-fs')

    // patching the global one
    const originalFs = require('fs')
    const gracefulFs = require('graceful-fs')
    gracefulFs.gracefulify(originalFs)

    mock-fs

    mock-fs 可以在文件系统模块中模拟数据, 这可以让你使用模拟的文件或者目录进行测试。

    用起来非常简单,请看下面的示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    const mock = require('mock-fs')  
    const fs = require('fs')

    mock({
    'path/to/fake/dir': {
    'some-file.txt': 'file content here',
    'empty-dir': {}
    },
    'path/to/some.png': new Buffer([8, 6, 7, 5, 3, 0, 9])
    })

    fs.exists('path/to/fake/dir', function (exists) {
    console.log(exists)
    // will output true
    })

    lockfile

    文件锁定是在同一时间只允许一个进程去操作文件。 这可以避免产生竞态条件。

    通过 lockfile 添加文件锁是非常简单的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    const lockFile = require('lockfile')

    lockFile.lock('some-file.lock', function (err) {
    // if the err happens, then it failed to acquire a lock.
    // if there was not an error, then the file was created,
    // and won't be deleted until we unlock it.

    // then, some time later, do:
    lockFile.unlock('some-file.lock', function (err) {

    })
    })

    总结

    我希望这篇文章对Node.js的文件系统讲解对你有用。

    如果你对这方面内容有问题,请在下面的评论中告诉我。

  •