node 内置模块之fs
本地文件操作模块 fs
fs 模块对文件的操作有异步和同步两种方式,例如:readFile() 和 readFileSync()
区别:
- 同步调用会阻塞代码的执行,异步不会
- 异步调用会将读取任务下达到任务队列,知道任务执行完成才会回调
- 异常处理:同步必须要使用 try catch 方式,异步可以使用回调函数的第一个参数 err 【重要】
文件读取
方法 | 说明 |
---|---|
readFile | 异步读取 |
readFileSync | 同步读取 |
createReadStream | 流式读取 |
const fs = require('fs')
// 异步
const data
try{
data = fs.readFileSync('./file1.txt','utf8')
console.log(data)
} catch(err) {
console.error('读取文件错误:' + err.message)
}
// 输出:
文件内容:Hello World!
// 同步
fs.readFile('./file1.txt','utf8',(err, dataStr) => {
if(err) return console.log('读取文件错误:' + err.message)
console.error(dataStr)
})
// 输出:
文件内容:Hello World!
从 Node.js 14 开始,fs 模块提供了两种使用基于 promises 的文件系统的方法。这些 promises 可以通过
require('fs').promises
或require('fs/promises')
获得
import { readFile } from 'fs/promises';
try {
const contents = await readFile(filePath, { encoding: 'utf8' });
console.log(contents);
} catch (err) {
console.error(err.message);
}
流式
const fs = require('fs')
let rs = fs.createReadStream(__dirname + '/grades.txt')
rs.on('data', chunk => {
console.log(chunk, chunk.length)
})
rs.on('end', () => console.log('ok'))
文件写入
方法 | 说明 |
---|---|
writeFile | 异步写入 |
writeFileSync | 同步写入 |
appendFile / appendFileSync | 追加写入 |
createWriteStream | 流式写入 |
如果文件不存在,则创建文件,如果文件存在,则覆盖文件内容
const fs = require('fs');
// 异步
fs.writeFile('./fileWrite.txt', 'hello world', 'utf8', function(err){
if(err) throw err;
console.log('文件写入成功');
});
// 同步
try{
fs.writeFileSync('./fileForWrite1.txt', 'hello world', 'utf8');
console.log('文件写入成功');
}catch(err){
throw err;
}
追加写入
// 异步
fs.append('./grades.txt', 'hello world', err =>{
if(err) throw err
console.log('追加成功')
})
// 同步
fs.appendFileSync('./grades.txt','\r\nHello World')
promises
import { writeFile } from 'fs/promises';
try {
const contents = await writeFile('message.txt', 'hello world', { encoding: 'utf8' });
console.log(contents);
} catch (err) {
console.error(err);
}
流式写入
let ws = fs.createWriteStream('./观书有感.txt')
//写入数据到流
ws.write('半亩方塘一鉴开\r\n')
ws.write('天光云影共徘徊\r\n')
ws.write('问渠那得清如许\r\n')
ws.write('为有源头活水来\r\n')
//关闭写入流,表明已没有数据要被写入可写流
ws.end()
程序打开一个文件是需要消耗资源的,流式写入可以减少打开关闭文件的次数
流式写入是用于大文件写入或者频繁写入的场景,writeFile 适合写入频繁较低的场景
文件读写小案例
// grades.txt
小王=100,小李=90,小陈=30,小高=80,小胖=99
// grades.js
const fs = require('fs')
fs.readFile(__dirname + '/grades.txt', 'utf8', (err, dataSrc) => {
if (err) return console.log('文件读取错误' + err)
const oldArr = dataSrc.split(',')
let newArr = []
oldArr.forEach(item => {
newArr.push(item.replace('=', ':'))
})
const newStr = newArr.join('\r\n')
// flag:a 表示如果存在该文件,就在文件末尾添加数据,不覆盖原先数据,appendFile
fs.writeFile(__dirname + '/grades-ok.txt', newStr, { encoding: 'utf8', flag: 'a' }, function (err) { if (err) return console.log('文件写入错误' + err) })
})
// grades-ok.txt
小王:100
小李:90
小陈:30
小高:80
小胖:99
文件移动与重命名
// 异步
fs.rename('./old.txt', './new/new.txt', err =>{
if(err) throw err
console.log('移动完成')
})
// 同步,省略了 try catch
fs.renameSync('./old.txt', './new/new.txt')
注意:如果还是移动到当前路径,但是修改了名字,就是重命名
文件删除
const fs = require('fs')
// 使用 unlink 和 unlinkSync
// 异步
fs.unlink('./test.txt', err => {
if(err) thorw err
console.log('删除成功')
})
// 同步
fs.unlinkSync('./test.txt')
// 使用 rm 和 rmSync
// 异步
fs.rm('./test.txt', err => {
if (err) {
console.log('删除失败')
return
}
console.log('删除成功')
})
// 同步
fs.rmSync('./test.txt')
文件夹操作
方法 | 说明 |
---|---|
mkdir / mkdirSync | 创建文件夹 |
readdir / readdirSync | 读取文件夹 |
rmdir / rmdirSync | 删除文件夹 |
mkdir 创建文件夹
// 异步创建文件夹
fs.mkdir('./page',err => {
if(err) throw err
console.log('创建成功')
})
// 异步递归创建
fs.mkdir('./grandfather/father/son',{recursive: true},err => {
if(err) throw err
console.log('递归创建成功')
})
// 同步递归创建
fs.mkdirSync('./grandfather/father/son',{recursive: true})
注意:同步创建已存在文件夹会报错
readdir 读取文件夹
// 异步读取
fs.readdir('./page', (err, data) => {
if(err) throw err
console.log(data)
})
// 同步读取
let data = fs.readdirSync('./page')
console.log(data)
// 读取指定文件夹下的全部文件
// 思路:同步读取该文件夹,遍历读取的文件夹,判断是否为文件或者目录,如果是文件就添加到数组中,如果是目录就递归调用该函数并且将数组拼接,最后返回数组
const fs = require('fs')
const path = require('path')
function readdirAll(dir){
let results = [path.resolve(__dirname,dir)]
const files = fs.readdirSync(dir,'utf8')
files.forEach(file => {
file = path.resolve(dir,file)
const stats = fs.statSync(file)
if(stats.isFile()){
results.push(file)
}else if(stats.isDirectory()){
results = results.concat(readdirAll(file))
}
});
return results
}
console.log(readdirAll('../'))
console.log(readdirAll('./'))
rmdir 删除文件夹
// 异步删除文件夹
fs.rmdir('./page',err=>{
if(err) throw err
console.log('删除成功')
})
// 异步递归删除,不推荐
fs.rmdir('./page',{recursive: true},err=>{
if(err) throw err
console.log('删除成功')
})
// 同步递归删除文件夹
fs.rmdir('./page',{recursive: true})
// 删除全部文件夹,建议使用
fs.rm('./page',{recursive: true},err=>{
if(err) {
console.log(err)
return
}
console.log('删除成功')
})
获取文件夹状态
1.异步:fs.stat(path,callback):
path是一个表示路径的字符串,callback接收两个参数(err,stats),其中stats就是fs.stats的一个实例;
2.同步:fs.statSync(path)
只接收一个path变量,fs.statSync(path)其实是一个fs.stats的一个实例;
方法:
- stats.isFile():是否为文件
- stats.iisDirectory():是否为目录(文件夹)
const fs = require('fs');
statsObj = fs.statSync("test_file.txt");
statsObj.isDirectory());
注意:上面遍历文件夹下的所有文件也是使用到了文件夹状态和两个方法