监控文件夹的变化

fs模块提供了FSWatcher类来辅助我们进行监控文件夹。

fs.watch(filename[, options][, listener])

示例代码:

const fs = require("fs");

// 监听文件夹变化:
// 1.
// 启动监听文件夹
let watcher = fs.watch(__dirname);

// 监听改变的事件
watcher.on('change', function(eventType, fileName){
    console.log('change: ', eventType, fileName);
});

// 关闭监听
setTimeout(() => {
    watcher.close(); // 实际: 关闭监听
}, 10000);

// 2.
let watcher2 = fs.watch(__dirname, function(eventType, fileName){
    console.log('callback: ', eventType, fileName);
});

// 关闭监听
setTimeout(() => {
    watcher2.close(); // 实际: 关闭监听
}, 10000);

读取文件下面所有的文件和文件夹

示例代码:

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

// 读取一个路径,返回路径下面所有的文件或文件夹的名字   
fs.readdir(__dirname, (err, files)=>{ // 异步方式
    // console.log(files);
    files.forEach((item, index)=>{
        fs.stat(path.join(__dirname, item), (err, stat)=>{
            if(err){
                console.log("error!");
                return;
            }
            stat.isFile() ? console.log("file", item) : console.log("dir", item);
            // console.log(stat);
        }); // 判断是文件还是文件夹

    });
});

读取文件

一次性读取小文件

示例代码:

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

// 读取当前文件的内容,此处设置了编码方式为utf8
// 同步方法,即当程序到此处时,整个程序会等文件读完,将内容赋值给filecontent
// ps:该方法会一次把整个文件读完(读到内存里),当遇到很大的文件时。。故只适合小文件。
let filecontent = fs.readFileSync(__filename, {
    encoding: 'utf8'
});

console.log(filecontent);

// 异步读取文件的方法:
// 主线程继续执行后续代码,线程池的线程读取文件内容。文件内容读取成功后,调用回调函数。
// 仅用于读取小文件。
let indexJSFileName = path.join(__dirname, "index.js"); 
fs.readFile(indexJSFileName, {
    encoding: "utf8"
}, function(err, data){
    console.log("文件读取完毕,执行回调函数。。");
    if(err){
        console.log("出现读取异常: ", err);
        return;
    }
    console.log(data);
});

console.log("主线程继续执行。。。");

读取大文件

采用path.createReadStream

步骤:

  1. 创建一个可读流
  2. 打开时触发open事件
  3. 来数据时触发data事件
  4. 读完时触发end事件

示例代码:

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

let fileName = path.join(__dirname, "a.pdf");
// 创建一个可读取的流
// let stream = fs.createReadStream(fileName, {
//     encoding: "utf8"
// });
let stream = fs.createReadStream(fileName);

// 当流的管道建立后并打开时,触发open事件
stream.on("open", function(fd){
    console.log("管道建立,并打开:fd", fd);
});

// data:当数据来的时候会触发这个事件
let i = 0;
stream.on("data", function(trunk){
    console.log("编号%d", i, trunk);
    i++;
});

stream.on("end", function(){
    console.log("数据读取完毕!");
});

写入文件

一次性写入少量文件

示例代码:

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

let aFilePath = path.join(__dirname, 'a.txt');

// 异步写入方式。
fs.writeFile(aFilePath, "你好,学习nodejs", function(err){
    if(err){
        console.log(err);
        return;
    }
    console.log("正常写入");
});

// 同步写入
// fs.writeFileSync(aFilePath, "hello~");

流的方式写入

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

// 用可写流,往 b.txt文件中写入100个字符串
let aFileName = path.join(__dirname, 'a.txt');

let stream = fs.createWriteStream(aFileName, {
    flags: 'a'
}); // 用追加的方式创建一个可写流


stream.on('open', function(fd){
    console.log("可写流打开 ", fd);
});

stream.on("close", function(){
    console.log("可写流关闭。");
});

// 往可写流里写入数据
for(let i = 0; i<100; i++){
    stream.write("learn!\n");
}

// 调用end方法,结束可写流
// stream.end(); // 内部不写也可以
stream.end("结尾!");

大文件的复制

1.通过读写流方式

原理图:

nodejs axios 下载文本文件 node下载文件夹_nodejs

参考代码:

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

let srcFile = path.join(__dirname, "a.pdf");
let destFile = path.join(__dirname, "b.pdf");

let rs = fs.createReadStream(srcFile); // 创建可读流
let ws = fs.createWriteStream(destFile);  // 创建写流

rs.on("open", function(fd){
    console.log("可是读取文件内容。。。");
});

rs.on("close", function(){
    console.log("读取结束!");
});

rs.on("data", function(trunk){
    if (ws.write(trunk) == false){ // 如果返回true表示还可以写,如果返回false表示不能再写了。
        // 缓冲区满了,不能再写了
        rs.pause(); // 让可读流暂停读取数据
    }
});

ws.on("drain", function(){
    // 可写流数据可以继续写入时,让可读流继续读数据。
    rs.resume();
});

2.通过管道的方式

示例代码:

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

let srcFile = path.join(__dirname, 'a.pdf');  // 源文件
let destFile = path.join(__dirname, 'c.pdf'); // 目标文件
let rs = fs.createReadStream(srcFile);  // 可读流
let ws = fs.createWriteStream(destFile); // 可写流

rs.pipe(ws);

递归读取一个文件夹下面所有的文件名字(包括子文件夹里的)

参考代码:

// 实现:
//    给一个名字:(注意检查名字是否合法,此处写的就是合法的,未对给定名字的合法性进行判断)
//           如果名字是文件,就直接打印
//           如果名字是文件夹,就读取其下的内容
//(采用递归的方式实现)

// 引入需要的内置模块
const fs = require("fs");
const path = require("path");

// let dirName = __dirname; // __dirname 当前工作目录
let dirName = "./test";

readDir(dirName); // 获取该目录下所有的文件及文件夹名字

function readDir(dirN){
    fs.readdir(dirN, (err, files)=>{
        if(err){
            console.log(err);
            return;
        }
        files.forEach((item, index)=>{
            // 对于每一个item,组装其完整路径
            comFileName = path.join(dirN, item);

            // 判断每一个comFileName是文件还是文件夹,是文件就输出文件名,是文件夹就进入文件夹读取输出其下的文件名
            fs.stat(comFileName, (err, stats)=>{
                if(err){
                    console.log(err);
                    return;
                }
                // 通过stat的isFile方法确定是路径还是文件夹
                // stats.isFile() ? console.log("file:", item, " ", comFileName) : console.log("dir:", item, " ", comFileName);
                if(stats.isFile()){
                    console.log(item);
                }else{
                    readDir(path.join(dirN, item)); // 如果是文件夹继续读取里面的
                }
            });            
        });
        
    });
}

待改进:

  1. 以树状图的方式显示一个文件夹内部的结构