10分钟闲聊Node.js中的fs模块

311 阅读1分钟

概念

Node.js 提供一组类似 UNIX(POSIX)标准的文件操作API。

const fs = require("fs");
  • fs提供了同步、回调和基于promise的三种形式。同步api会阻塞线程,但对于某些场景,使用同步方法会更方便、更易理解
  • 尽量使用promise方式,回调容易造成嵌套地狱
  • 对于大文件,使用文件流的方式来读写文件 createReadStream 和 createWriteStream 来减少内存占用
  • 三方npm包 fs-extra 是fs的一个拓展,提供了很多更方便的api

打开文件

fs.open(path, flags[, mode], callback)

flags参数

用于描述打开文件的模式,例如r为读取模式、r+为读写模式等等
打开一个文件,若文件不存在,是报错还是新建,这些都可以通过该参数设置

文件描述符

一个文件描述是 open 以及 openSync 方法调用返回的一个数字。可用于操作文件,例如读、写

const fd = fs.openSync('./file', 'a');
console.log(typeof fd === 'number'); // true

读写文件

readFile
fs.readFile('./file.txt',(err,data)=>{
  if(err){
    console.error(err);
    return;
  }
  // 转换的是buffer,要用toString转换
  console.log(data.toString());
});

read
const fs = require('fs')

fs.open('./file.text', 'r+', (err, fd) => { //flags: 'r+'  打开文件用于读写,修改文件时使用
    if(err) {
        console.error(err)
        return
    }

    //创建一个buffer类型的变量content来存储读取到的数据
    const content = Buffer.alloc(6)

    fs.read(fd, content, 0, 6, 24, (err,bytesRead, buffer) => {
        if(err) {
            console.error(err)
            return
        }
        //buff和字符串通过'+'拼接,会被转换为字符串,再去拼接
        console.log('读取到的数据是:' + buffer)
    })
})
readFileSync
const data = fs.readFileSync('./file.txt');
console.log(data.toString());
读写流
const fs = require('fs');
const readable = fs.createReadStream('./original.txt');
const writeable = fs.createWriteStream('./copy.txt');
readable.pipe(writeable);
逐行读取
const fs = require('fs');
const readline = require('readline');

const rl = readline.createInterface({
  input: fs.createReadStream('/etc/hosts'),
  crlfDelay: Infinity
});

rl.on('line', (line) => {
  console.log(`cc ${line}`);
  const extract = line.match(/(\d+\.\d+\.\d+\.\d+) (.*)/);
});

获取文件信息

通过异步的方式获取文件信息:

fs.stat('./file', (err,stats) => {
  console.log(stats.isFile());   // 该文件是否是文件
})

文件锁

如果有多个进程操作同一文件,可能会造成文件信息错误,这时候就需要一个锁来保证文件操作的完整性

独占标记

// 所有需要打开文件的方法,fs.writeFile、fs.createWriteStream、fs.open 都有一个 x 标记
// 这个文件应该已独占打开,若这个文件存在,文件不能被打开
fs.open('config.lock', 'wx', (err) => {
  if (err) { console.error(err); return;}
});

// 最好将当前进程号写进文件锁中
// 当有异常的时候就知道最后这个锁的进程
fs.writeFile(
  'config.lock',
  process.pid,
  { flags: 'wx' },
  (err) => {
    if (err) { console.error(err); return };
  },
);

mkdir文件锁

独占标记有个问题,可能有些系统不能识别 0_EXCL 标记。另一个方案是把锁文件换成一个目录,PID 可以写入目录中的一个文件

fs.mkidr('config.lock', (err) => {
  if (err) { console.error(err); return}
  fs.writeFile(`/config.lock/${process.pid}`, (err) => {
    if (err) { console.error(err); return }
  });
});

watch文件

监听一个文件或目录,当它们发生改变时执行一定操作

const fs = require('fs');
fs.watch('./watchdir', console.log); // 稳定且快
fs.watchFile('./watchdir', console.log); // 跨平台