【Node文件系统fs模块】

环境:Node v8.2.1; Npm v5.3.0; OS Windows10

1、fs 模块API

nodejs的文件操作大部分API都提供了同步和异步的两种方式,下面是异步API结构图,同步方法在异步方法后面加【Sync】就行了

1.1 API结构图

《【Node文件系统fs模块】》

1.2 文件读写模式对应编码

《【Node文件系统fs模块】》

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模块】同步更新

    原文作者:BLUE
    原文地址: https://segmentfault.com/a/1190000011386968
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞