Node.js必知必会学习笔记(第二章)

518 阅读3分钟

场景需求一:判断服务器上面有没有upload目录,如果没有,则创建这个目录,如果有的话不做操作


实现方法一:

步骤一:封装一个根据传入目录路径的参数创建目录的函数

const fs=require('fs');
function mkdir(dir){
    fs.mkdir(dir,(err)=>{
        if(err){
            console.log(err);
            return;
        }
    })
}

步骤二:定义一个目标目录路径的变量(path),先用fs.stat判断有没有upload目录,如果有upload但是upload不是目录的话,先去执行删除upload文件再去执行创建upload目录

var path='./upload'
fs.stat('./upload',(err,data)=>{
    if(err){
        //执行创建目录
        mkdir(path)
        return;
    }
    if(!data.isDirectory()){
        console.log('upload不是目录')
        //首先先去删除文件再去执行创建目录
        fs.unlink(path,(err)=>{
            if(!err){
                mkdir(path);
            }else{
                console.log('请检查传入的数据是否正确')
            }
        })
    }
})

实现方法二:

步骤一:cnpm i mkdirp --save
步骤二:var mkdirp =require('mkdirp');
步骤三:
mkdirp('./upload').then(made =>
    console.log(`made directories, starting with ${made}`))

场景需求二:wwwroot文件下下面有img css js 以及index.html,找出wwwroot 目录下面的所有目录,然后放在一个数组里面

该构建目录结构为:黄色框为入口文件代码

失败的方法一之错误的写法:没有考虑到异步给代码带来的影响

场景带入:

for(var i=0;i<3;i++){
    setTimeout(function(){
        console.log('i', i)
    },100)
}  // i 3 i 3 i 3
function getData(){
    //ajax
    setTimeout(function(){
        var name='张三'
    },1000)
    return name;
}

// //外部获取异步方法里面的数据
console.log(getData())  //name is not defined
//通过回调函数获取异步方法里面的数据

function getData(callback){
    //ajax
    setTimeout(function(){
        var name='张三';
        callback(name)
    },1000)

}

//外部获取异步方法里面的数据
getData(function(name){
    console.log(name)
})

失败的方法一的基本思路:声明一个空数组(dirArr)和一个目标路径('./wwwroot'),利用fs.readdir对目标路径目录进行读取,如果该目录下有目录可读取数据会保存在data里,接着对data数据进行循环遍历筛选,想要利用fs.statdata中判断为目录的数据放进数组dirArr中。

失败的方法一:
var dirArr=[];
var path='./wwwroot'
fs.readdir(path,(err,data)=>{
    if(err){
        console.log(err);
        return;
    }
    console.log('data',data)  //第二被执行--数据确实有

    for(var i=0;i<data.length;i++){
        fs.stat(path+'/'+data[i],(error,stats)=>{
            if(stats.isDirectory()){
                dirArr.push(data[i])
            }
        })
    }
    console.log('dirArr111', dirArr)
})

console.log('dirArr222', dirArr) //第一被执行--因为fs.readdir异步
失败的方法一总结:

for循环中的 fs.stat 是异步方法,
在for循环执行中时 data 中的数据无法和预期结果一致 

改造的成功的方法二的基本思路利用IIFE和递归实现

var dirArr=[];
var path='./wwwroot'
fs.readdir(path,(err,data)=>{
    if(err){
        console.log(err);
        return;
    }
    

    (function getDir(i){
        if(i==data.length){
            console.log('dirArr', dirArr)
            return;
        }
        fs.stat(path+'/'+data[i],(error,stats)=>{
            if(stats.isDirectory()){
                dirArr.push(data[i])
            }
            getDir(i+1)
        })

    })(0)
})

改造的进阶的方法三的基本思路:通过async 和 await。先定义一个isDir的方法判断一个资源到底是目录还是文件,该方法如果是目录返回true,不是则返回false,再去获取wwwroot里面的所有资源循环遍历判断

async function isDir(path){
        return new Promise((resolve,reject)=>{
            fs.stat(path,(error,stats)=>{
                if(error){
                    console.log(error)
                    reject(error)
                }
                if(stats.isDirectory()){
                    resolve(true)
                }else{
                    resolve(false)
                }
            })
        })
}

function main(){
    var path='./wwwroot'
    var dirArr=[];
    fs.readdir(path, async (err,data)=>{
        //---await得用在async的方法里面
        if(err){
            console.log(err);
            return;
        }

        for(var i=0;i<data.length;i++){
            if(await isDir(path+'/'+data[i])){
                dirArr.push(data[i])
            }
        }

        console.log(dirArr)
    })
}
main();

async和await的使用思路:

/**
 * async'异步'的简写,await可以认为是async的简写。
 * 所以很好理解async用于申明一个异步的function,
   而await用于等待一个异步方法执行完成
 * 
 * 简单理解
 * async是把方法变成异步
 * await是等待异步方法执行完成
 */

//普通方法
function test(){
    return '你好node.js'
}
console.log(test())  //你好node.js



async function test(){
    return '你好node.js'
}
console.log(test()) //Promise { '你好node.js' }

错误的写法:

错误的写法:
错误的写法:
错误的写法:

async function test(){
    return '你好node.js'
}

console.log( await test()) //错误

---await得用在async的方法里面
---await得用在async的方法里面
---await得用在async的方法里面

正确的写法:

正确的写法:
正确的写法:
正确的写法:

async function test(){
    return '你好node.js'
}

async function main(){
    var data=await test(); //获取异步方法里面的数据
    console.log(data)
}

main(); /你好node.js

通过async封装一个异步方法并返回一个promise


async function test() {
    return new Promise((res,rej)=>{
        setTimeout(()=>{
            var name='异步数据';
            res(name)
        },100)
    })
}
//await得用在async的方法里面
async function main(){
    var data=await test();
    console.log(data) //异步数据
}
main();

  • 该构建目录的结构为:

  • readFileSync读取文件
//当文件过大时会发生内存爆仓
const fs = require("fs");
// let res = fs.readFileSync("1.txt");
// console.log(res.toString());
  • fs.createReadStream 从文件流中读取数据
var fs=require('fs')

var readStream=fs.createReadStream('./input.txt')

var count=0;
var str='';
//监听读取数据的事件
//监听流的数据
readStream.on('data',(data)=>{
    str+=data;
    count++;
})

readStream.on('end',()=>{
    console.log(str,count)
})


readStream.on('error',(err)=>{
    console.log(err)
})

fs.createWriteStream从文件流中写入数据

var fs=require('fs');
var data= '我是从数据库获取的数据,我要保存起来';
var str='';
for(var i=0;i<500;i++){
    str+='我是从数据库获取的数据,我要保存起来/n'
}

var writeStream=fs.createWriteStream('./ouput.txt')

writeStream.write(str);

//标记写入完成--才能触发finish
writeStream.end();

writeStream.on('finish',()=>{
    console.log('写入完成')
})

一边创建可读流一边创建可写流进行普通读写操作

//创建一个可读流
var readStream=fs.createReadStream('./input.txt')
//创建一个可写流
var writeStream=fs.createWriteStream('./ouput.txt')
//普通读写操作
//读取input.txt文件内容并将内容复制写入到ouput.txt文件中
readStream.pipe(writeStream)
console.log('执行成功')

  • 案例一:边创建一个65kb的文件的可读流,边创建可写流的文件并导入进去65kb的文件
const fs = require("fs");

//创建可读流
let rs = fs.createReadStream("65kb");
//buffer打印了两次说明数据被拆分了两次

//创建可写流
let ws = fs.createWriteStream("2.txt");

//边读边写
rs.pipe(ws);


let num = 0;
let str = "";
rs.on("data",chunk=>{
    num++;
    str += chunk;
    // console.log(chunk);
    console.log(num);  //2  读取两次
})
// 流读取完成了的事件;
rs.on("end",()=>{
    console.log(str); //再这里读取完整的数据
})




// 流会把数据分成64kb的小文件(64kb一组)传输;
// 创建一个65kb的文件
let buffer = Buffer.alloc(65*1024);
fs.writeFile("64kb",buffer,err=>{
    if(err){
        return console.log(err);
    }
    console.log("写入成功");
})