Node 文件IO

165 阅读2分钟

Node 文件 IO

fs 模块

  • 在Node中只有require的相对路径是针对当前文件的文件目录的,内置 path 模块的 join 和 resolve 都是相对process.cwd()命令路径,Node中的全局变量 __dirname 的值是当前执行脚本文件所在的文件目录的完整路径
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;
  }

  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 result = path.resolve(this.filename, name);
      return File.getFile(result);
    });
    return Promise.all(children);
  }

  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);;l
    const updateTime = new Date(stat.mtime);
    return new File(filename, name, ext, isFile, size, createTime, updateTime);
  }
}

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);
  const datas = await result[0].getChildren();
  console.log(datas);
}

test();

大文件读写流 Stream

流是指数据的流动,数据从一个地方缓慢的流动到另一个地方,在Node中使用stream模块进行使用
由于其他介质和内存的

  • 数据规模不一致,磁盘里面可以装很多的数据,但是内存小里面可以装的数据很少,所以在读大数据的时候,不可能把磁盘里面的大数据一下子读到内存,只能一部分一部分的读。
  • 数据处理能力不一致,内存处理能力很快,硬盘的速度和内存是没有办法比的,1G 的内存中的数据全部往硬盘里面塞,就会造成对硬盘的阻塞,所以用流缓慢的存。

变量存在内存中,流的使用一般是读一部分扔一部分,如果在data中将所有的chunk收集流的数据规模特性就发挥不到了 普通读写和流读写之间的区别

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

//方式1
async function method1() {
  const from = path.resolve(__dirname, "./temp/abc.txt");
  const to = path.resolve(__dirname, "./temp/abc2.txt");
  console.time("方式1");
  const content = await fs.promises.readFile(from);
  await fs.promises.writeFile(to, content);
  console.timeEnd("方式1");
  console.log("复制完成");
}

//方式2
async function method2() {
  const from = path.resolve(__dirname, "./temp/abc.txt");
  const to = path.resolve(__dirname, "./temp/abc2.txt");
  console.time("方式2");

  const rs = fs.createReadStream(from);
  const ws = fs.createWriteStream(to);
  rs.on("data", chunk => {
    //读到一部分数据
    const flag = ws.write(chunk);
    if (!flag) {
      //表示下一次写入,会造成背压
      rs.pause(); //暂停读取
    }
  });

  ws.on("drain", () => {
    //可以继续写了
    rs.resume();
  });

  rs.on("close", () => {
    //写完了
    ws.end(); //完毕写入流
    console.timeEnd("方式2");
    console.log("复制完成");
  });
}

method2();

上述可以直接用pipe实现读写复制

const fs = require("fs");
const path = require("path");
//方式2
async function method2() {
  const from = path.resolve(__dirname, "./temp/abc.txt");
  const to = path.resolve(__dirname, "./temp/abc2.txt");
  console.time("方式2");
  const rs = fs.createReadStream(from);
  const ws = fs.createWriteStream(to);

  rs.pipe(ws);

  rs.on("close", () => {
    console.timeEnd("方式2");
  });
}
method2();