NodeJS全集(三)

105 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情

文件I/O

I/O:input/output,对外部设备的输入输出。
IO 的速度往往低于内存和 CPU 的交互速度。

磁盘、网卡、显卡、打印机...都是外部设备。

fs 模块

fs 模块中绝大部分 API 都是异步模式,跟计算机硬盘交互。 不推荐使用 Sync 模式进行操作,因为 Sync 函数是同步的,会导致JS运行阻塞,及其影响性能。
通常,在程序启动时运行有限次数即可。

在 ES6 的promise API 出现后,读取文件 api 变为了 Promise 模式。但是为了兼容性,仍然保留了 Sync 的 API。

  • readFile:读取一个文件
  • writeFile:向文件写入内容
  • stat:获取文件或目录信息
  • readdir:获取目录中的文件和子目录
  • mkdir:创建目录
  • exists:判断文件或目录是否存在

读取一个目录中所有子目录和文件:

const fs = require('fs');
const path = require('path');

// 创建一个文件信息类
class File {
    constructor(filename, name, ext, isFile, size, createTime, updateTime) {
        this.filename = filename;
        this.name = name;
        this.ext = ext;
        this.isFile = isFile;
        this.size = size
        this.createTime = createTime;
        this.updateTime = updateTime;
    }

    static async getFile(filename) {
        const stat = await fs.promises.stat(filename);
        const name = path.basename(filename);
        const ext = path.extname(filename);
        const isFile = stat.isFile();
        const size = stat.size;
        const createTime = new Date(stat.birthtime);
        const updateTime = new Date(stat.mtime);
        return new File(filename, name, ext, isFile, size, createTime, updateTime)
    }

    async getContent(isBuffer = false) {
        if (this.isFile) {
            if (isBuffer) {
                return await fs.promises.readFile(this.filename);
            }
            else{
                return await fs.promises.readFile(this.filename, 'utf-8');
            }
        }
        return null;
    }

    async getChildren(){
        if (this.isFile) {
            return [];
        }
        let children =  await fs.promises.readdir(this.filename);
        children =  children.map(name => {
            const res = path.resolve(this.filename, name);
            return File.getFile(res)
        })
        return Promise.all(children) ;
    }
}
// 读取文件信息
async function readDir(dirname){
    const file = await File.getFile(dirname);
    return await file.getChildren();
}
// 测试
async function test(){
    const dirname = path.resolve(__dirname, "./myFiles");
    const result = await readDir(dirname);
    console.log(result);
}

test()

文件流

文件流是流的一种,当我们读取的文件不是一个文本文件而是一张图片或是音频...大体积文件。计算机硬盘的容量是非常大的,但是内存的空间却是有限的。如果直接读取的方式,那所有的数据都会被挤压在内存里面。我们不希望一次性全读出来,而是一部分一部分的读取。

流是指数据的流动,数据从一个地方缓缓的流动到另一个地方,这个过程就称为流。

流是有方向的,不同语言对流的含义不一样。在 node js里面分为:

  • 可读流:数据从源头流向内存
  • 可写流:数据从内存流向源头
  • 双工流:数据即可从源头流向内存又可以从内存流向源头

使用流主要解决这些问题:其他介质和内存的数据规模不一致,其他介质和内存数据处理能力不一致。

文件流

内存数据和磁盘文件之间的流动

在 node 的stream 模块中有两个构造函数,Readable、Writable 来实现流。

文件流的创建

const fs = require("fs");
const path = require("path");

const filename = path.resolve(__dirname, "./abc.txt");
const rs = fs.createReadStream(filename, {
    encoding: 'utf-8', // 编码方式
    highWaterMark: 1// 每次读取的大小,根据encoding值运算方式不同
    autoClose: true, // 读完后会自动关闭
})



// 注册事件
fs.on("open", function () {
    console.log('文件被打开')
})

fs.on('error', function(){
    console.log('出错了')
})

fs.on('close', function(){
    console.log('文件关闭')
})

fs.on('data', function(chunk){
    console.log('读到了一部分数据', chunk)
})

fs.on('pause', function(){
    console.log('暂停')
})

fs.on('resume', function(){
    console.log('恢复')
})