环境:Node v8.2.1; Npm v5.3.0; OS Windows10
1、fs 模块API
nodejs的文件操作大部分API都提供了同步和异步的两种方式,下面是异步API结构图,同步方法在异步方法后面加【Sync】就行了
1.1 API结构图
1.2 文件读写模式对应编码
2、一些例子
下面是部分API的例子,对部分API的一个简单代码实现
2.1 readFile读取文件
//readFile(filename,[options],callback);
/**
* filename, 必选参数,文件名
* [options],可选参数,可指定flag(文件操作选项,如r+ 读写;w+ 读写,文件不存在则创建)及encoding属性
* callback 读取文件后的回调函数,参数默认第一个err,第二个data 数据
*/
const fs = require("fs");
fs.readFile('./package.json',{flag:"r+",encoding:"utf8"},(err,data)=>{
if(err)
throw err;
console.log(data);
})
2.2 writeFile写文件
// fs.writeFile(filename,data,[options],callback);
/**
* filename, 必选参数,文件名
* data, 写入的数据,可以字符或一个Buffer对象
* [options],flag,mode(权限),encoding
* callback 读取文件后的回调函数,参数默认第一个err,第二个data 数据
*/
const fs = require("fs");
const data="hello world";
const bf=Buffer.from(data);
//buffer写入
fs.writeFile("./test.txt",bf,err=>{
if(err)
throw err;
console.log("写入成功");
})
//字符写入
fs.writeFile("./test.txt",data,err=>{
if(err)
throw err;
console.log("写入成功");
})
2.3 以追加方式写文件
// fs.appendFile(filename,data,[options],callback);
const fs = require("fs");
const data = " hello world";
const bf = Buffer.from(data);
//buffer
fs.appendFile("./test.txt", bf, err => {
if (err)
throw err;
console.log("追加成功");
})
fs.appendFile("./test.txt", data, err => {
if (err)
throw err;
console.log("追加成功");
})
2.4 open打开文件
打开文件,获取文件描述
// fs.open(filename, flags, [mode], callback);
/**
* filename, 必选参数,文件名
* flags, 操作标识,如"r",读方式打开
* [mode],权限,如777,表示任何用户读写可执行
* callback 打开文件后回调函数,参数默认第一个err,第二个fd为一个整数,表示打开文件返回的文件描述符,window中又称文件句柄
*/
const fs = require("fs");
fs.open("./test.txt","r",0666,(err,fd)=>{
if(err)
throw err;
console.log(fd); //3
})
【0666】为【文件权限码】,也可以在【fs.constants】中输出
2.5 读文件,读取打开的文件内容到缓冲区中
//fs.read(fd, buffer, offset, length, position, callback);
/**
* fd, 使用fs.open打开成功后返回的文件描述符
* buffer, 一个Buffer对象,v8引擎分配的一段内存
* offset, 整数,向缓存区中写入时的初始位置,以字节为单位
* length, 整数,读取文件的长度
* position, 整数,读取文件初始位置;文件大小以字节为单位
* callback(err, bytesRead, buffer), 读取执行完成后回调函数,bytesRead实际读取字节数,被读取的缓存区对象
*/
const fs = require("fs");
fs.open("./test.txt", "r", (err, fd) => {
if (err)
throw err;
let bf = Buffer.alloc(255);
fs.read(fd,bf,0,9,0,(err,bytesRead,buffer)=>{
if(err)
throw err;
console.log(bytesRead);
console.log(buffer.toString());
})
})
2.6 写文件,将缓冲区内数据写入使用fs.open打开的文件
//fs.write(fd, buffer, offset, length, position, callback);
/**
* fd, 使用fs.open打开成功后返回的文件描述符
* buffer, 一个Buffer对象,v8引擎分配的一段内存
* offset, 整数,从缓存区中读取时的初始位置,以字节为单位
* length, 整数,从缓存区中读取数据的字节数
* position, 整数,写入文件初始位置;
* callback(err, written, buffer), 写入操作执行完成后回调函数,written实际写入字节数,buffer被读取的缓存区对象
*/
const fs = require("fs");
fs.open("./test.txt", "w", (err, fd) => {
if (err)
throw err;
let bf = Buffer.from(" 写入文件数据的内容");
fs.write(fd, bf, 0, bf.length, 0, (err, bytesWritten, buffer) => {
if (err)
throw err;
console.log(bytesWritten);
console.log(`写入的内容:${buffer.toString()}`);
})
})
2.7 刷新缓存区
使用fs.write写入文件时,操作系统是将数据读到内存,再把数据写入到文件中,当数据读完时并不代表数据已经写完,因为有一部分还可能在内在缓冲区内。
因此可以使用fs.fsync方法将内存中数据写入文件;--刷新内存缓冲区;
//fs.fsync(fd, [callback])
/**
* fd, 使用fs.open打开成功后返回的文件描述符
* [callback(err, written, buffer)], 写入操作执行完成后回调函数,written实际写入字节数,buffer被读取的缓存区对象
*/
const fs = require("fs");
fs.open("./test.txt", "a+", (err, fd) => {
if (err)
throw err;
let bf = Buffer.from(" I love Node");
fs.write(fd, bf, 0, bf.length, 0, (err, bytesWritten, buffer) => {
if (err)
throw err;
fs.fsync(fd,(err)=>{});
fs.close(fd,err=>{});
})
})
2.8 读取目录
//使用fs.readdir读取目录,重点其回调函数中files对象
//fs.readdir(path, callback);
/**
* path, 要读取目录的完整路径及目录名;
* [callback(err, files)], 读完目录回调函数;err错误对象,files数组,存放读取到的目录中的所有文件名
*/
const fs = require("fs"),
path = require("path");
fs.readdir(__dirname + "/../11文件系统fs", (err, files) => {
if (err)
throw err;
files.forEach(file => {
let filePath = path.normalize(__dirname + '/' + file);
fs.stat(filePath, (err, stats) => {
if (stats.isFile()) {
console.log(filePath + ' is: ' + 'file');
}
if (stats.isDirectory()) {
console.log(filePath + ' is: ' + 'dir');
}
})
})
})
3、流操作
3.1 创建读取流
//fs.createReadStream(path, [options])
/**
* path 文件路径
* [options] flags:指定文件操作,默认'r',读操作;encoding,指定读取流编码;autoClose, 是否读取完成后自动关闭,默认true;start指定文件开始读取位置;end指定文件开始读结束位置
*/
const fs = require("fs");
const rs = fs.createReadStream("./package.json", { flags: "r" });
rs.on("open", fd => console.log('开始读取文件'));
rs.on('data', data => {
console.log(data.toString());
})
rs.on('end', function () {
console.log('读取文件结束')
});
rs.on('close', function () {
console.log('文件关闭');
});
rs.on('error', function (err) {
console.error(err);
});
3.2 创建写入流
//fs.createWriteStream(path, [options])
/**
* path 文件路径
* [options] flags:指定文件操作,默认'w',;encoding,指定读取流编码;start指定写入文件的位置
*/
/* ws.write(chunk, [encoding], [callback]);
* chunk, 可以为Buffer对象或一个字符串,要写入的数据
* [encoding], 编码
* [callback], 写入后回调
*/
/* ws.end([chunk], [encoding], [callback]);
* [chunk], 要写入的数据
* [encoding], 编码
* [callback], 写入后回调
*/
const fs = require("fs");
const ws=fs.createWriteStream("./test.txt",{flags:"w"})
const bf=Buffer.from("I Love Node");
ws.on('open', function () {
console.log('文件流开启')
});
ws.on('close', function () {
console.log('文件流关闭');
});
ws.on('error', function (err) {
console.error(err);
});
ws.write(bf,"utf8",(err,buffer)=>{
console.log('写入完成')
})
ws.end(' Bye');
3.3 使用流复制文件
流复制文件就是创建一个读取流和一个写入流,将读取流中的流出的数据用写入流进行写入
//使用流复制文件
const fs = require("fs");
const rs = fs.createReadStream("./package.json");
const ws = fs.createWriteStream("./package1.json");
rs.on("data", data => {
ws.write(data);
})
ws.on('open', function (fd) {
console.log('要写入的数据文件已经打开,文件描述符是: ' + fd);
});
rs.on("end",()=>{
console.log('文件读取完成');
ws.end('完成',()=>{
console.log("文件写入完成");
})
})
关于WriteStream对象的write方法返回一个布尔类型,当缓存区中数据全部写满时,返回false;表示缓存区已经写满,并将立即输出到目标对象中。
一个例子测试返回值:
const fs = require("fs");
var ws = fs.createWriteStream(__dirname + '/test.txt',{flags:"w"});
for (var i = 0; i < 10000; i++) {
var w_flag = ws.write(i.toString());
//当缓存区写满时,输出false
console.log(w_flag);
}
一个例子当缓存区数据全部输出时,触发事件
const fs = require("fs");
const rs = fs.createReadStream("./ABoy.mp3");
const ws = fs.createWriteStream("./ABoy1.mp3");
rs.on("data", data => {
let t = ws.write(data);
if(!t){
console.log(t);
}
})
ws.on("drain", () => {
console.log('系统缓存区数据已经全部输出。')
})
3.4 pipe管道用于流
上面使用一个读取流额一个写入流进行了一次文件的复制,还有另外一种方式就是在写入流和读取流之间建立一条管道,是读取流中的数据通过管道源源不断的流向写入流,实现文件的复制。
const fs = require("fs");
const rs = fs.createReadStream("./ABoy.mp3");
const ws = fs.createWriteStream("./ABoy1.mp3");
rs.pipe(ws);
rs.on('data', function (data) {
console.log('数据可读')
});
rs.on('end', function () {
console.log('文件读取完成');
});
ws.on("drain", () => {
console.log('系统缓存区数据已经全部输出。')
});
ws.on('open', function (fd) {
console.log('要写入的数据文件已经打开,文件描述符是: ' + fd);
});
CSDN 【Node文件系统fs模块】同步更新
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。