Skip to content

1.promise、callback、sync

js
// promise
const path = require('node:path')
const fs = require('node:fs/promises');
(async function(path) {
  try {
    await fs.unlink(path)
    console.log(`successfully deleted ${path}`)
  } catch (error) {
    console.error('there was an error:', error.message)
  }
})(path.resolve(__dirname, './test.txt'))
js
// callback
const path = require('node:path')
const fs = require('node:fs')
const target = path.resolve(__dirname, './test.txt')
fs.unlink(target, (err) => {
  if (err) throw err
  console.log(`successfully deleted ${target}`)
})
js
// sync
const path = require('node:path')
const fs = require('node:fs')
const target = path.resolve(__dirname, './test.txt')
try {
  fs.unlinkSync(target)
  console.log(`successfully deleted ${target}`)
} catch (err) {
  throw err
}

2.file-handle

在 Node.js 中,FileHandle 是一个表示打开文件的对象,提供了多种方法来操作文件内容。FileHandle 通常通过 fs.promises.open() 方法获取。

打开文件

使用 fs.promises.open() 方法可以异步打开文件,并返回一个 FileHandle 对象。

js
const fs = require('node:fs/promises');

async function openFile() {
  try {
    const fileHandle = await fs.open('example.txt', 'r');
    console.log('File opened successfully');
    // 进行文件操作
    await fileHandle.close();
  } catch (err) {
    console.error('Error opening file:', err);
  }
}

openFile();

读取文件

使用 fileHandle.read() 方法可以从文件中读取数据。

js
async function readFile() {
  try {
    const fileHandle = await fs.open('example.txt', 'r');
    const buffer = Buffer.alloc(1024);
    const { bytesRead } = await fileHandle.read(buffer, 0, buffer.length, 0);
    console.log('Bytes read:', bytesRead);
    console.log('Data:', buffer.toString('utf8', 0, bytesRead));
    await fileHandle.close();
  } catch (err) {
    console.error('Error reading file:', err);
  }
}

readFile();

写入文件

使用 fileHandle.write() 方法可以向文件中写入数据。

js
async function writeFile() {
  try {
    const fileHandle = await fs.open('example.txt', 'w');
    const data = 'Hello, Node.js!';
    const { bytesWritten } = await fileHandle.write(data);
    console.log('Bytes written:', bytesWritten);
    await fileHandle.close();
  } catch (err) {
    console.error('Error writing file:', err);
  }
}

writeFile();

关闭文件

完成文件操作后,使用 fileHandle.close() 方法关闭文件句柄以释放资源。

js
async function closeFile() {
  try {
    const fileHandle = await fs.open('example.txt', 'r');
    // 进行文件操作
    await fileHandle.close();
    console.log('File closed successfully');
  } catch (err) {
    console.error('Error closing file:', err);
  }
}

closeFile();

3.constants

Node.js 中,constants 模块包含了各种操作系统特定的常量,这些常量用于文件系统操作、错误码、信号等。

js
const fs = require('node:fs')

console.log(fs.constants)

4.fs.access

fs.access 方法用来判断文件是否可访问:

  • F_OK 0 文件是否存在(默认值)
  • R_OK 1 文件是否可读
  • W_OK 2 文件是否可写
  • X_OK 4 文件是否可执行
js
const path = require('node:path')
const fs = require('node:fs')

// 检测文件是否有执行权限
const access = fs.accessSync(path.resolve(__dirname, './3.constants.js'), fs.constants.X_OK)

console.log(access)

5.fs.appendFile

fs.appendFileSync(path, data[,options])

  • 向目标文件中追加文本内容
  • 如果目标文件不存在的话 会自动创建
js
const path = require('node:path')
const fs = require('node:fs')

const result = fs.appendFileSync(path.resolve(__dirname, './test.txt'), 'Hello World\n')
console.log(result)

6-1.chmod&chown

fs.chmodSync(path, mode)

fs.chownSync(path, uid, gid)

chmod 即为 change mode更改模式chown 即为 change owner更改所有权

js
const path = require('node:path')
const fs = require('node:fs')

const result = fs.chmodSync(path.resolve(__dirname, './6.chmod&chown.js'), 0o765)
console.log(result)

TIP

0o765是八进制

  • 0 没有许可
  • 1 只执行
  • 2 只写
  • 3 写和执行
  • 4 只读
  • 5 读取和执行
  • 6 读取和写
  • 7 读写和执行

6-2.fchmod&fchown

fs.fchmodSync(fd, mode)

fs.fchownSync(fd, uid, gid)

fd 全称为 file descriptor文件描述符

js
const fs = require('node:fs')

// 使用 chownSync 更改文件路径为 'example.txt' 的文件所有者和群组
fs.chownSync('example.txt', 1000, 1000)

// 打开文件并获取文件描述符
const fd = fs.openSync('example.txt', 'r')

// 使用 fchownSync 更改文件描述符为 fd 的文件所有者和群组
fs.fchownSync(fd, 1000, 1000)

// 关闭文件描述符
fs.closeSync(fd)

7-1.open&close

文件描述符:

  • fchmod(fd)
  • fchown(fd)
  • readSync(fd)
js
const path = require('node:path')
const fs = require('node:fs')

const fd = fs.openSync(path.resolve(__dirname, './7-2.opendir&close.js'), 'r')

console.log(fd)

7-2.opendir&close

opendirSync 是一个同步函数,用于打开一个目录并返回一个 fs.Dir 对象。这个对象可以用来读取目录中的内容。

当使用 fs.opendirSync 打开一个目录时,会创建一个 fs.Dir 对象,并且底层操作系统资源(例如文件描述符)会被分配给该对象。

这些资源是有限的,如果不及时释放,可能会导致资源耗尽或其他潜在的问题。

因此,在使用 opendirSync 之后,要调用 closeSync 方法进行关闭。

readdirSync 读取整个目录的内容并返回一个包含目录条目名称的数组。它一次性读取所有条目,适用于简单的场景。

js
const path = require('node:path')
const fs = require('node:fs')

const dir = fs.opendirSync(path.resolve(__dirname, '../'))

// console.log(dir)
let dirent
while ((dirent = dir.readSync()) !== null) {
  console.log(dirent)
}

// 关闭目录
dir.closeSync()

8.copyFile & cp

js
// 复制某文件到新文件 如果 `dest` 已存在,则操作会覆盖
fs.copyFileSync(src, dest[,mode])

// 复制目录到新目录
fs.cpSync(src, dest[,options])

9.existsSync

fs.existsSync(path)

如果 path 路径存在,则返回 true,否则为 false

注意,这里的 path 指代的是路径,那么也就是无论是目录还是文件,都是可以的。

js
const fs = require('node:fs')
const path = require('node:path')

const dirResult = fs.existsSync(path.resolve(__dirname, '../1.assertion-testing'))

const fileResult = fs.existsSync(path.resolve(__dirname, './8.copyFile&cp.js'))

console.log(dirResult, fileResult)

10.mkdirSync

js
// fs.mkdirSync 创建目录

const path = require('node:path')
const fs = require('node:fs')

// 如果目录已存在的话 会报错。所以可以使用fs.existsSync方法提前判断
fs.mkdirSync(path.resolve(__dirname, '../1.assertion-testing'))

11.readdirSync

fs.readdirSync(path[,options]) 读取目标目录,并列出目标目录下的目录和文件。

options: { encoding: 'utf8', withFileTypes: false, recursive: false }

如果 recursive 设置为 false 那么则会递归读取目录所有文件、子文件以及目录。

js
const path = require('node:path')
const fs = require('node:fs')

const result = fs.readdirSync(path.resolve(__dirname, '../../assets'), {
  // encoding: 'utf8',
  recursive: true // node较高版本,才可能生效,譬如v20.9.0
})

console.log(result)

12.readFileSync

fs.readFileSync(path[,options])

options 中包括:

  • encoding 编码方式 默认为 null
  • flag 文件系统标志 默认为 r

如果指定了 encoding,返回一个字符串,表示文件内容。 如果未指定 encoding,返回一个 Buffer,表示文件的二进制数据。

js
const path = require('node:path')
const fs = require('node:fs')

const result = fs.readFileSync(path.resolve(__dirname, './11.readdirSync.js'), {
  encoding: 'utf8'
})

console.log(result)

13.renameSync

fs.renameSync(oldPath, newPath)

Renames the file from oldPath to newPath. Returns undefined.

js
const path = require('node:path')
const fs = require('node:fs')

fs.renameSync(path.resolve(__dirname, './12.readFileSync.js'), path.resolve(__dirname, './11.readFileSync.js'))

14.rmdirSync & rmSync

  1. rmdirSync 删除目录(不推荐使用)
  2. rmSync 删除文件或目录
js
const path = require('node:path')
const fs = require('node:fs')

const dirPath = path.resolve(__dirname, '../../src/pages')

// 删除目录的话 需要声明recursive参数 否则报错ENOTEMPTY 另外控制台会有警告,主要大意就是 `recursive` param is deprecated,推荐使用fs.rmSync结合recursive参数进行使用
fs.rmdirSync(dirPath, {
  recursive: true
})

// 删除目录的话 需要声明recursive参数 否则报错EISDIR
// fs.rmSync(dirPath, {
//   recursive: true
// })

15.statSync

js
const path = require('node:path')
const fs = require('node:fs')

// const targetPath = path.resolve(__dirname, './14.rmdirSync&rmSync.js')
const targetPath = path.resolve(__dirname, '../')

// 获取文件或者目录的信息 包含文件大小 访问时间 内容修改时间 权限更改事件。
const stat = fs.statSync(targetPath)
console.log(stat)

/*
Stats {
  dev: 16777220,
  mode: 16877,
  nlink: 62,
  uid: 501,
  gid: 20,
  rdev: 0,
  blksize: 4096,
  ino: 122242453,
  size: 1984,
  blocks: 0,
  atimeMs: 1718523576164.7617,
  mtimeMs: 1718456959556.3726,
  ctimeMs: 1719632506024.8196,
  birthtimeMs: 1718285449381.608,
  atime: 2024-06-16T07:39:36.165Z,
  mtime: 2024-06-15T13:09:19.556Z,
  ctime: 2024-06-29T03:41:46.025Z,
  birthtime: 2024-06-13T13:30:49.382Z
}
*/
js
// 获取文件系统信息 包含文件系统的各种属性,如总大小、可用空间、块大小等。无论targetPath设置为什么,同一个系统的执行结果是一样的。
const statfs = fs.statfsSync(targetPath)
console.log(statfs)

/*
StatFs {
  type: 26,
  bsize: 4096,
  blocks: 61202533,
  bfree: 3031215,
  bavail: 3031215,
  files: 129382624,
  ffree: 121248600
}
*/

16.unlinkSync

fs.unlinkSync(path)

unlinkSync 用于删除指定路径的文件或符号链接。

  • 删除文件:unlinkSync 用于从文件系统中删除指定路径的文件。
  • 删除符号链接:如果指定路径是一个符号链接,那么 unlinkSync 会删除该符号链接,而不会删除它指向的目标文件。
js
const path = require('node:path')
const fs = require('node:fs')

const result = fs.unlinkSync(path.resolve(__dirname, './1.promise&callback&sync.js'))

console.log(result)

17.writeFileSync

fs.writeFileSync(file, data[,options])

options:

  • encoding 默认 utf8
  • mode 默认 0o666
  • flag 默认 w
  • flush
  1. 如果该操作,作用于目录,报错 illegal operation on a directory
  2. 如果该操作指定的目标不存在,则会自动创建
  3. 该操作会覆盖文件的原始内容 而不是追加
js
const path = require('node:path')
const fs = require('node:fs')

const result = fs.writeFileSync(path.resolve(__dirname, './test.txt'), '123\n456')

console.log(result)

18.createReadStream

fs.createReadStream创建可读流

node 中读取文件的方式有来两种,一个是利用 fs 模块,一个是利用流来读取。

如果读取小文件,我们可以使用 fs 读取,fs 读取文件的时候,是将文件一次性读取到本地内存。而如果读取一个大文件,一次性读取会占用大量内存,效率很低,这个时候需要用流来读取。

流是将数据分割段,一段一段的读取,可以控制速率,效率很高,不会占用太大的内存。

gulptask 任务,文件压缩,和 http 中的请求和响应等功能的实现都是基于流来实现的。

js
const path = require('node:path')
const fs = require('node:fs')

const stream = fs.createReadStream(path.resolve(__dirname, './17.writeFileSync.js'), {
  highWaterMark: 64, //文件一次读多少字节,默认 64*1024
  flags: 'r', //默认 'r'
  autoClose: true, //默认读取完毕后自动关闭
  start: 0, //读取文件开始位置
  // end:3, //默认为Infinity
  encoding: 'utf8' //默认为null 此时返回的是Buffer
})

// 打开流
stream.on('open', () => {
  console.log('打开流')
})

// 读取流
stream.on('data', (data) => {
  console.log('data---', data)
})

// 读取错误
stream.on('err',() => {
  console.log('读取错误')
})

//读取结束
stream.on('end',() => {
  console.log('读取结束')
})

//读取关闭
stream.on('close',() => {
  console.log('读取关闭')
})

// 读取暂停
// stream.pause()

// 读取恢复
// stream.resume()

19.createWriteStream

fs.createWriteStream创建可写流

写入流 可以想象成 水流通过水管向水池中进行注入的过程,而对于水管,我们会称作“缓存区”,水池则是“目标文件”。

当每次写入完成,也就是水管中的水注入完了之后,都会触发 drain 方法。

js
const path = require('node:path')
const fs = require('node:fs')

const filePath = path.resolve(__dirname, './writeStream.txt')

const stream = fs.createWriteStream(filePath, {
  flags: 'w',
  encoding: 'utf8',
  start: 0,
  highWaterMark: 3
})

let i = 9
// 写入9876543210
function write() {
  let flag = true
  while (flag && i >= 0) {
    flag = stream.write(i-- + '')
    console.log(flag)
  }
}

//缓存区充满并被写入完成,处于清空状态时触发
stream.on('drain',() => {
  console.log('drain')
  //当缓存区清空后我们在继续写
  write()
})

write() //第一次调用write方法