fs
Nodejs中,fs模块即文件系统模块(File System module)提供了与文件系统进行交互的各种功能
fs模块是Nodejs核心API之一,可以执行读取文件、写入文件、更改文件权限、创建目录等操作
选项
可以使用配置项flag指定一些操作方式
'a'
:打开文件进行追加,如果文件不存在,则创建该文件'ax'
:类似于'a'
,但如果路径存在则失败。'a+'
:打开文件进行读取和追加,如果文件不存在,则创建该文件'ax+'
:类似于'a+'
,但如果路径存在则失败'as'
:以同步模式打开文件进行追加,如果文件不存在,则创建该文件'as+'
:以同步模式打开文件进行读取和追加,如果文件不存在,则创建该文件'r'
:打开文件进行读取,如果文件不存在,则发生异常'r+'
:打开文件进行读写,如果文件不存在,则发生异常'rs+'
:以同步模式打开文件进行读写,指示操作系统绕过本地文件系统缓存- 主要用于在NFS挂载上打开文件,因为它允许跳过可能过时的本地缓存
- 它对I/O性能有非常实际的影响,因此除非需要,否则不建议使用此标志
- 它不会将
fs.open()
或fsPromises.open()
变成同步阻塞调用,如果需要同步操作,应该使用类似 fs.openSync()
的东西。
'w'
:打开文件进行写入,创建(如果它不存在)或截断(如果它存在)该文件'wx'
:类似于'w'
,但如果路径存在则失败'w+'
:打开文件进行读写,创建(如果它不存在)或截断(如果它存在)该文件'wx+'
:类似于'w+'
,但如果路径存在则失败
读取文件
fs返回的是一个buffer二进制数据,每两个十六进制数字表示一个字节
1
| <Buffer e4 bd a0 e7 88 b1 e6 88 91 ef bc 8c e6 88 91 e7 88 b1 e4 bd a0 ef bc 8c e8 9c 9c e9 9b aa e5 86 b0 e5 9f 8e e7 94 9c e8 9c 9c e8 9c 9c>
|
想要获取文字,需要进一步调用toString方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const fs = require('node:fs') const fs2 = require('node:fs/promises')
fs.readFile('./index.txt', { encoding: 'utf-8', flag: 'r' }, (err, data) => { if (err) throw err console.log(data.toString(), 111) })
const data = fs.readFileSync('./index.txt') console.log(data.toString(), 222)
fs2.readFile('./index.txt').then(data => { console.log(data.toString(), 333) }).catch(err => { console.log(err) })
|
流式读取文件,适用于读取大文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const fs = require('node:fs') const fs2 = require('node:fs/promises')
const readStream = fs.createReadStream('index.txt')
readStream.on('data', (chunk) => { console.log(chunk.toString()) })
readStream.on('end', () => { console.log('读取完成~') })
|
写入文件
命名方式和读取文件一样,带有Sync字样的是同步方法,不带则是异步方法,下同
1 2 3 4 5 6 7 8 9 10 11 12
| const fs = require('node:fs')
fs.writeFileSync('index.txt', '早上好中国,现在我有蜜雪冰城')
fs.writeFileSync('index.txt', '\n我很喜欢冰淇淋,但是,雪王驾到', { flag: 'a' })
fs.appendFileSync('index.txt', '\n你碍我,我碍你,你学编程天灭你~')
|
同样,也可以流式写入文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| const fs = require('node:fs')
let data = [ 'Hello World1', 'Hello World2', 'Hello World3', 'Hello World4', 'Hello World5', 'Hello World6', 'Hello World7', 'Hello World8', 'Hello World9', 'Hello World10' ]
let writeStream = fs.createWriteStream('index.txt')
data.forEach((item) => { writeStream.write(item + '\n') })
writeStream.end()
writeStream.on('finish', () => { console.log('写入完成') })
|
文件夹
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const fs = require('node:fs')
fs.mkdirSync('./test')
fs.mkdirSync('./test2/foo/bar', { recursive: true })
fs.rmSync('./test')
fs.rmSync('./test2', { recursive: true })
|
重命名
1 2 3 4 5
| const fs = require('node:fs')
fs.renameSync('index.txt', 'index2.txt')
|
监听文件变化
1 2 3 4 5 6 7
| const fs = require('node:fs')
fs.watch('./index2.txt', (event, filename) => { console.log(event, filename) })
|
创建硬/软链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const fs = require('node:fs')
fs.linkSync('index.txt', 'index2.txt')
fs.symlinkSync('index.txt', 'index3.txt')
|
注意事项
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const fs = require('node:fs')
fs.readFile('./index.txt', 'utf8', (err, data) => { if (err) { console.error(err) return } console.log(data) })
setImmediate(() => { console.log('immediate') })
|
按理说,异步读取文件的操作也会被推入本轮事件循环,在setImmediate之前执行,但结果却是这样
因为所有fs操作都由libuv调度,而所有计时器都由v8引擎调度
当libuv完成任务后,才会将其推入V8的事件队列,所以它会延后执行