Node.js 中 fs.stat 详解

9,581 阅读4分钟

Node.js 中 fs.statfs.statSync 方法可以获取文件信息,例如:

const fs = require('fs')
const stat = fs.statSync('./a.txt')
console.log(stat)

会返回一个 fs.Stats 对象,打印出来的效果如下:

Stats {
  dev: 16777221,
  mode: 33188,
  nlink: 1,
  uid: 501,
  gid: 20,
  rdev: 0,
  blksize: 4096,
  ino: 16908736,
  size: 3860,
  blocks: 8,
  atimeMs: 1618116564133.5427,
  mtimeMs: 1618116561126.6218,
  ctimeMs: 1618116561126.6218,
  birthtimeMs: 1618116561110.9902,
  atime: 2021-04-11T04:49:24.134Z,
  mtime: 2021-04-11T04:49:21.127Z,
  ctime: 2021-04-11T04:49:21.127Z,
  birthtime: 2021-04-11T04:49:21.111Z
}

异步的 fs.stat 方法接收 3 个参数:

  1. path <string> | <Buffer> | <URL>
  2. options <Object>
    • bigint <boolean> 返回的 fs.Stats 对象中的数值是否为 bigint 型。 默认值是 false。
  3. callback <Function>
    • err <Error>
    • stats <fs.Stats>

fs.Stats 对象

调用 fs.statfs.statSync 方法返回的 fs.Stats 对象上,有很多实用的属性和方法,例如可以通过 stat.isDirectory() 判断是否是文件夹,以及通过 stat.size 属性获取文件大小,接下来就详细介绍 fs.Stats 对象中的属性和方法:

isBlockDevice

  • 语法:stats.isBlockDevice()
  • 返回:<boolean>
  • 描述:如果描述了一个块设备,则返回 true

isCharacterDevice

  • 语法:stats.isCharacterDevice()
  • 返回:<boolean>
  • 描述:如果描述了一个字符设备,则返回 true

isDirectory

  • 语法:stats.isDirectory()
  • 返回:<boolean>
  • 描述:如果描述一个文件系统目录,则返回 true

isFIFO

  • 语法:stats.isFIFO()
  • 返回:
  • 描述:如果描述了一个先进先出管道,则返回 true

isFile

  • 语法:stats.isFile()
  • 返回:<boolean>
  • 描述:如果描述了一个正常的文件,则返回 true。

isSocket

  • 语法:stats.isSocket()
  • 返回:<boolean>
  • 描述:如果描述一个 socket,则返回 true

isSymbolicLink

  • 语法:stats.isSymbolicLink()
  • 返回:<boolean>
  • 描述:如果描述一个符号链接,则返回 true
  • 备注:这个方法只有使用 fs.lstat() 时才有效

dev

  • 语法:stats.dev
  • 返回:<number>|<bigint>
  • 描述:包含文件的设备的数字描述符

ino

  • 语法:stats.ino
  • 返回:<number>|<bigint>
  • 描述:文件系统为文件特定的 Inode 数字

mode

  • 语法:stats.mode
  • 返回:<number>|<bigint>
  • 描述:一个位字段描述文件类型和模式

nlink

  • 语法:stats.nlink
  • 返回:<number> | <bigint>
  • 描述:文件存在的硬链接数

uid

  • 语法:stats.uid
  • 返回:<number>|<bigint>
  • 描述:拥有文件的数字用户标识符

gid

  • 语法:stats.gid
  • 返回:<number> | <bigint>
  • 描述:拥有文件的数字组标识符

rdev

  • 语法:stats.rdev
  • 返回:<number>|<bigint>
  • 描述:如果文件被当做”特殊的”的数字设备标识符

size

  • 语法:stats.size
  • 返回:<number>|<bigint>
  • 描述:文件有多少个字节

blksize

  • 语法:stats.blksize
  • 返回:<number>|<bigint>
  • 描述:文件系统用于i/o操作的块的大小

blocks

  • 语法:stats.blocks
  • 返回:<number>|<bigint>
  • 描述:为文件分配的块数

atimeMs

  • 语法:stats.atimeMs
  • 返回:<number>|<bigint>
  • 描述:最近一次访问文件的时间戳(以 POSIX Epoch 以来的毫秒数计算)

ctimeMs

  • 语法:stats.ctimeMs
  • 返回:<number>|<bigint>
  • 描述:最近一次文件状态的修改的时间戳(以 POSIX Epoch 以来的毫秒数计算)

birthtimeMs

  • 语法:stats.birthtimeMs
  • 返回:<number>|<bigint>
  • 描述:文件创建时间的时间戳(以 POSIX Epoch 以来的毫秒数计算)

atime

  • 语法:stats.atime
  • 返回:<Date>
  • 描述:文件最近一次被访问的时间戳

mtime

  • 语法:stats.mtime
  • 返回:<Date>
  • 描述:文件最近一次修改的时间戳

ctime

  • 语法:stats.ctime
  • 返回:<Date>
  • 描述:文件最近一次状态变动的时间戳

birthtime

  • 语法:stats.birthtime
  • 返回:<Date>
  • 描述:文件创建的时间戳

fs.State 对象中的时间值

state 对象中的时间有以下语义:

  • atime:Access Time,表示文件最近被访问的时间

    mknod(2)utimes(2)、和 read(2) 系统调用时改变

  • mtime:Modified Time,表示文件最近被修改的时间

    mknod(2)utimes(2)、和 write(2) 系统调用时改变

  • ctime:Change Time,表示文件 inode 数据被修改的时间

    chmod(2)chown(2)link(2)mknod(2)rename(2)unlink(2)utimes(2)read(2)write(2) 系统调用时改变

  • birthtime:Birth Time,表示文件的创建时间

    utimes(2) 系统调用时改变

一定要注意,ctime 并非表示创建时间,而是修改时间,对文件进行任何修改都会影响到 ctime,例如用 chmod 改文件的权限只影响 ctime 但是不会影响 mtime,也就是说只要 mtime 发生变化,ctime一定会变但反之则不然。

atime、mtime、ctime 和 birthtime 都是 Date 对象,代表各种各样的时间,除了上面的日期类型之外,还有与其对应的保存响应的毫秒数的数字:

  • atimeMs
  • mtimeMs
  • ctimeMs
  • birthtimeMs

这个数字可能是 number 类型,也可能是 bigint 类型,如果在 options 中的 bigint 为 true,则数值会是bigint。另外需要注意,Date和数字值没有关联,当分配一个新的数字值或者改变 Date 值时,都不影响其他值。

fs.stat 方法的变体

fs.stat 方法有下面两个变体:

  • fs.lstat()
  • fs.fstat()

lstatstat 基本相同,区别在于:如果 path 是链接,lstat 读取的是链接本身,而不是它所链接到的文件。statlstat接收的第一个参数是一个文件路径字符串,但 fstat 就不太一样了,它接收的是一个文件描述符,例如:

const fs = require('fs')
const fd = fs.openSync('./a.txt')
console.log(fd)
const stat = fs.fstatSync(fd)
console.log(stat)

文件描述符(FD:file descriptors),是指当某个程序打开文件时,内核返回的一个正整数,程序为了处理该文件必须引用此描述符,用以标明每一个被进程所打开的文件和 socket。