每天学习一个nodejs模块-fs

826 阅读5分钟

这是我参与更文挑战的第1天,活动详情查看: 更文挑战

文件读写模块fs

fs是nodejs中提供的用于读写文件系统的模块,可以用于文件的读写,复制,追加,删除等操作,每个文件api都提供异步和同步两种方式,比如读取文件提供同步方法readFileSync和异步方法readyFile,其中异步方法为错误优先回调,可以通过util模块提供的promisify方法将错误优先回调的api转换为Promise风格api(本文大部分以这种风格进行代码实例展示)。接下来就说一下fs模块的基本操作

读取文件

函数签名为:fs.readFile(filename, [encoding], [callback(error, data)]) readFile一共接收三个参数,filename为文件名称,encoding为文件字符编码(可选参数,如果传递会返回解析后的内容,不传的话会返回Buffer),callback为错误优先的回调函数,用来获取文件内容,具体代码如下

const fs = require('fs');
const {promisify} = require('util');
const {resolve} = require('path');
const readFile = promisify(fs.readFile);
const filename = resolve(__dirname, 'test.txt');

(async () => {
    const data = await readFile(filename);
    console.log(data); // <Buffer e8 bf 99 e6 98 af e4 b8 80 e4 b8 aa e6 b5 8b e8 af 95 e6 96 87 e6 9c ac>
    const str = await readFile(filename, 'utf-8');
    console.log(str); // 这是一个测试文本
})()

写入文件

函数签名为:fs.writeFile(filename, data, [options], callback) writeFile一共可以接受四个参数,filename为文件名称,data为写入数据,options为可选参数,指定文件编码方式encoding,文件的读写权限mode,文件追加方式flag,默认为w,重写文件操作,a为追加操作,callback为错误优先回调,具体代码如下

(async () => {
    const data = await writeFile(filename, '测试测试', {flag: 'w'})
    console.log(data); // 文件内容变为测试测试 w为覆盖写入操作
    const str = await writeFile(filename, '测试测试', {flag: 'a'})
    console.log(str); // 文件内容变为测试测试测试测试 a为追加写入操作
})()

追加文件内容

函数签名为:fs.appendFile(filename, data, [options], callback) appendFile一共可以接收四个参数,其中filename为文件名称,data为追加数据,options和writeFile一致,只是文件追加方式flag为a,callback为错误优先回调,具体代码如下

(async () => {
    const data = await appendFile(filename, '这是在测试fs.appendFile方法')
    console.log(data); // undefined 此时文件内容变为 测试测试这是在测试fs.appendFile方法
    const str = await appendFile(filename, '测试测试', {flag: 'w'})
    console.log(str); // 文件内容变为测试测试 w为覆盖写入操作
})()

复制文件内容

函数签名为:fs.copyFile(filename1, filename2, callback) copyFile一共接收三个参数,filename1为原始文件名,filename2为新文件名称,callback为错误优先回调,具体如下:

(async () => {
    const data = await copyFile(filename, 'copy_test.txt');
    console.log(data); // undefined
})()

删除文件

函数签名为:fs.unlink(filename, callback) unlink方法一共可以接受两个参数,filename为要删除文件名称,callback为错误优先回调,具体如下

(async () => {
    const data = await unlink('copy_test.txt');
    console.log(data); // undefined
})()

读取文件状态

函数签名为:fs.stat(filename, callback) stat方法一共接收两个参数,filename为读取文件,callback为错误优先回调,值得一提的是,callback的第二个参数中有一些关键信息,比如文件最后一次访问时间,最后一次修改时间,文件的大小,是否是目录,是否是文件等信息,所以这个时候就无法使用promisify进行Promise的处理,当然也可以自己封装一个promisify进行处理,接下来的文章会说自定义promisify进行处理第二个参数(不要急,往后看),api操作如下:

const fs = require('fs');
const promisify = require('./promisify');
const {resolve} = require('path');
const stat = promisify(fs.stat);
const filename = resolve(__dirname, 'test.txt');
(async () => {
    const data = await stat('test.txt');
    console.log(data.size); // 12 文件大小
    console.log(data.atime.toLocaleString()); // 2021/6/8 下午8:27:46 文件最后一次访问时间
    console.log(data.birthtime.toLocaleString()); // 2021/6/8 下午8:06:18 文件创建时间
    console.log(data.mtime.toLocaleString()); // 2021/6/8 下午8:27:45 文件最后一次修改时间
    console.log(data.ctime.toLocaleString()); // 2021/6/8 下午8:27:45 文件状态发生变化时间
    console.log(data.isFile()); // true 是否是文件
    console.log(data.isDirectory()); // false 是否是目录
})()

读取指定目录中所有文件名称

函数签名为:fs.readdir(path, [options], callback) readdir一共接收三个参数,path为读取目录,options为可选参数,可以指定编码方式encoding,默认为utf-8,可以指定读取的文件类型withFileTypes,默认为false,为true时会读取当前目录下文件的具体类型,callback为错误优先回调,具体代码如下:

const fs = require('fs');
const promisify = require('./promisify');
const {resolve} = require('path');
const readdir = promisify(fs.readdir);

(async () => {
    const data = await readdir(resolve(__dirname, '../'));
    console.log(data); // [ '.git', '.gitignore', '20210608', 'LICENSE', 'README.md' ]
    const items = await readdir(resolve(__dirname, '../'), {withFileTypes: true});
    console.log(items);
    /**
    Dirent { name: '.git', [Symbol(type)]: 2 },
    Dirent { name: '.gitignore', [Symbol(type)]: 1 },
    Dirent { name: '20210608', [Symbol(type)]: 2 },
    Dirent { name: 'LICENSE', [Symbol(type)]: 1 },
    Dirent { name: 'README.md', [Symbol(type)]: 1 }
    ]
     */
})()

文件系统中读取文件,文件夹,创建文件,文件夹此类的操作还有很多,就不一一赘述了,当我们知道这些api之后搭配nodejs其他模块就可以做一些常用的小功能了,比如借助HTTP模块和FS模块搭建我们自己的静态资源服务器,比如通过FS模块的API在我们当前项目中进行一些简单页面的读取搭建等,还是非常有用的,接下来在最后说一下promisify如何自定义吧

自定义promisify

首先promisify建立在错误优先回调的基础上,默认的promisify无法将错误优先回调的第二个参数返回到我们,那我们有必要自己来写一个自定义版本的。我们先来分析一下,错误优先回调是每个api的最后一个参数,是不是我们利用promiseApi将函数执行,并且根据函数的执行结果进行resolvereject的调用就可以了呢,具体如下:

module.exports = function promisify(fn) {
    return function (...args) {
        return new Promise(function (resolve,reject) {
            args.push(function (err,...arg) {
                if(err){
                    reject(err)
                }else{
                    resolve(...arg);
                }
            });
            fn.apply(null, args);
        })
    }
}

本文涉及到的模块具体如下

  1. fs文件操作模块
  2. path文件路径模块(还有很多有趣的api)
  3. util工具模块

本文代码路径

github地址