node.js入门笔记(四)——fs模块、crypto加密、原生静态资源目录

node.js入门笔记(四)

      • 1.内置模块fs
        • 1.1文件目录操作
        • 1.2文件操作
        • 1.3文件监听
        • 1.4node.js的流操作与文件压缩
        • 1.5readline逐行读取数据
        • 1.6 Crypto内置加密模块
      • 2.node.js路由基础
      • 3.node.js后端静态资源目录搭建

    首先解释一下为什么我这个标题都长这么随意,一般别人都是按内容分模块的来写。其实是因为我学习都是按照技术点来的,如果断断续续的看印象不深,因此一次性看的内容比较多,不好区分什么是重点,所以就不纠结标题了,如果觉得好可以看看专栏里面的其他内容。好啦,废话不多说了,直接开始吧。

1.内置模块fs

node.js中内置了fs文件操作模块,含有基本的文件增删查改(通常简称为crud,也就是create,remove,update,delete,由于文件修改和文件读写都需要时间,因此都是异步操作)。下面主要展示常用的api:

1.1文件目录操作

(1)创建文件mkdir

const fs = require("fs");
fs.mkdir("./logs", (err) => {
    if (err) throw err;
    console.log("创建文件目录成功");
});

需要注意的是,这里遵循的是错误优先规则,因此首先需要检测err才能执行之后的操作,比如:如果两次重复创建,err遍会生效。
(2)修改目录名rename(同样错误优先):

const fs = require("fs");
fs.rename("./logs", "log", (err) => {
    if (err) throw err;
    console.log("文件目录名修改成功!");
});

(3)删除文件夹rmdir(错误优先,只能删除空文件夹):

const fs = require("fs");
fs.rmdir("./log", (err) => {
    if (err) throw err;
    console.log("文件夹删除成功!");
});

(4)查找文件夹readdir(错误优先,读取目录下的文件信息变成了数组,只能往下读一级):

const fs = require("fs");
fs.readdir("./log", (err, res) => {
    if (err) throw err;
    console.log("输出问价夹中的内容:", res);
});
1.2文件操作

(1)向文件中书写内容writeFile

const fs = require("fs");
fs.writeFile("./logs/log.log", "hello\nworld!", (err) => {
    if (err) throw err;
    console.log("数据写入成功!");
});

需要注意的是,如果没有文件,那么会直接创建文件并写入内容,但是如果文件前面的目录也不存在,会直接抛错。重复写入相同文件会直接覆盖文件中原有的内容。
(2)向文件中写入内容appendFile

fs.appendFile("./logs/log.log", "hello world!", (err) => {
    if (err) throw err;
    console.log("追加内容成功!");
});

(3)读取文件中的内容readFile

fs.readFile("./logs/log.log", (err, res) => {
    if (err) throw err;
    console.log("输出数据:", res.toString());
});

需要注意的是,读取文件之后的内容为二进制数据,需要进一步使用toString函数来转化。其次文件读写有两种函数(同步readFileSync和异步readFile),Synchronous(同步的)Asynchronous(异步的),异步处理写法如下:

const content = fs.readFileSync("./logs/log.log");
console.log(content.toString());
console.log("waiting...");

在文件系统中,fs还能够利用promise将同步转化成异步操作:
node.js入门笔记(四)——fs模块、crypto加密、原生静态资源目录_第1张图片
最后用上上面的函数可以得到一个递归搜索文件内容的函数:

const fs = require("fs");
const targetDir = "../file-manager";

(function searchDir(dir) {
    let dirList = new Array();
    fs.readdir(dir, (err1, res1) => {
        if (err1) throw err1;
        dirList = res1;
        if (dirList.length) {
            dirList.forEach((item, index) => {
                let subdir = dir + "/" + item;
                fs.stat(subdir, (err2, res2) => {
                    if (err2) throw err2;
                    if (res2.isDirectory()) {
                        searchDir(subdir);
                    } else {
                        console.log("输出文件目录:", subdir);
                        console.log(fs.readFileSync(subdir).toString());
                    }
                });
            });
        }
    });
})(targetDir);

(4)读取文件中的内容unlink

const fs = require("fs");
fs.unlink("./logs/log.log", (err) => {
    if (err) throw err;
    console.log("删除文件成功!");
});

结合上面的函数,能够得到如下的文件清空程序(目录中内容非空无法删除):

const fs = require("fs");
const targetDir = "./logs";
(function clearDir(dir) {
    fs.readdir(dir, (err1, res1) => {
        if (err1) throw err1;
        const dirList = res1;
        if (dirList.length) {
            dirList.forEach((item, index) => {
                let tempDir = dir + "/" + item;
                console.log("当前需要处理的目录:", tempDir);
                fs.stat(tempDir, (err2, res2) => {
                    if (err2) throw err2;
                    if (res2.isDirectory()) {
                        clearDir(tempDir);
                    } else {
                        fs.unlink(tempDir, (err3) => {
                            if (err3) throw err3;
                        });
                    }
                });
            });
        } else {
            fs.rmdir(dir, (err) => {
                if (err) throw err;
            });
        }
    });
})(targetDir);

逻辑差了点,这个只能删除最深一层的数据。如果你想写的更秀一点,直接给出一个目录删除全部的子文件夹和目录,欢迎在评论区指点我一波(暴力多次深度遍历除外,这个太费时了,不太科学)。通过查阅api文档发现有实现这种递归删除的函数(害,算法不行,还得靠大佬):

fs.rm(targetDir, { recursive: true }, (err) => {
    if (err) throw err;
    console.log("文件删除成功!");
});
1.3文件监听
const fs = require("fs");
fs.watch("./log.txt", (res) => {
    console.log(res);
    console.log("文件发生改变");
});

主要能够监听两种情况,renamechange,移动文件位置、重命名(前两个都属于rename事件)或者修改内容都能够触发watch监听事件。{ recursive: true }可以产生递归监听效果。需要明确的是还有一种监听方法watchFile。两者相比较而言,内部实现的逻辑不一样,watch函数的跨平台性有一定的弱点,主要支持windows和macos。建议优先使用watchFile。对于目录的监听主要监听文件目录下的文件创建和删除,被监听目录的名称变化,而不会监听子文件中内容的变化,响应之后会产生回调函数类似于fs.stat函数的前后两次调用,watchFile还能够设置轮询时长:

import { watchFile } from 'fs';
watchFile('message.txt', (curr, prev) => {
  console.log(`更改后的stat信息: ${curr.mtime}`);
  console.log(`更改前的stat信息: ${prev.mtime}`);
});
1.4node.js的流操作与文件压缩

例如利用文件的读写流实现简单的文件复制:

const fs = require("fs");
let readData = fs.createReadStream("./index.html");
let writeData = fs.createWriteStream("./index-back.html");
readData.pipe(writeData);

对于这种数据流,还可以进行中间操作,就相当于利用一根管子,将一个文件中的数据流传入另一个文件里面,中间可以进行“过滤”等操作。

const fs = require("fs");
const zlib = require("zlib");
const gzip = zlib.createGzip();
let readData = fs.createReadStream("./index.html");
let writeData = fs.createWriteStream("./index-back.gzip");
readData.pipe(gzip).pipe(writeData);
1.5readline逐行读取数据
const readline = require("readline");
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
});
rl.question("你如何看待node.js?", (answer) => {
    console.log(`感谢你的宝贵意见:${answer}`);
});

程序执行效果如下:
在这里插入图片描述
有点像命令行的味道,有类似于js的prompt弹出框,扩展了node.js的业务面。

1.6 Crypto内置加密模块

直接给出一个例子吧,具体的加密方式还得看实际的要求(下面使用的是sha256加密,然后转化成了十六进制)。

const crypto = require("crypto");
const password1 = "admin123";
console.log(
    "输出加密之后的数据:",
    crypto.createHash("sha256").update(password).digest("hex")
);

2.node.js路由基础

node.js内置模块总算是看了个大概,接下来就是比较结合实践的路由了。和其他后端一样,node.js路由就是希望处理url,为用户暴露出接口。首先给出一个简单的例子:

const http = require("http");
const https = require("https");
const fs = require("fs");
const server = http.createServer((req, res) => {
    const urlString = req.url;
    switch (urlString) {
        case "/html":
            const content = fs.readFileSync("./index.html");
            res.write(content);
            res.end();
            break;
        case "/test.js":
            const js = fs.readFileSync("./test.js");
            res.write(js);
            res.end();
            break;
        case "/lovely.jpg":
            const image = fs.readFileSync("./lovely.jpg");
            res.write(image);
            res.end();
            break;
        default:
            res.write("This is default content.");
            res.end();
    }
    console.log("你的请求地址是:", req.url);
});
server.listen(8080, () => {
    console.log("localhost:8080");
});

解释一下这里为什么写了这么多关于资源加载的,其实如果通过后端,就必须将这些文件封装成数据流发送给前端形成前端请求的接口。但是不可能为每一个文件都写一个接口。分析接口之间的特点,我们可以只封装文件读取,直接发送给前端交由浏览器来自动辨别我们传输的数据类型。但是,这样是不太清晰的。
解决方法是使用mime依赖,安装依赖npm install mime -Smime中的getType函数能够直接根据后缀名快速判断文件数据传输时候的类型,然后修改文件获取的代码:

 const urlString = req.url;
 const type = urlString.substring(urlString.lastIndexOf("."));
 const targetType = mime.getType(type);
 const file = fs.readFileSync(`.${urlString}`);
 res.writeHead(200, {
     "content-type": targetType,
 });
 res.write(file);
 res.end(file);

3.node.js后端静态资源目录搭建

代码倒好说,主要是搭建的目录形式,其实和thinkPHP后端框架差不多:
node.js入门笔记(四)——fs模块、crypto加密、原生静态资源目录_第2张图片
附上程序代码:

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

function readData(dir, res) {
    if (fs.existsSync(dir)) {
        dirStr = String(dir);
        const targetType = mime.getType(dirStr.substring(dirStr.lastIndexOf(".")));
        const content = fs.readFileSync(dir);
        res.writeHead(200, {
            "content-type": targetType + ";charset=utf-8;",
        });
        res.end(content);
    } else {
        res.end("The file or floder not found!");
    }
}
const server = http.createServer((req, res) => {
    const pathDir = path.resolve(__dirname, "./public") + req.url;
    fs.stat(pathDir, (err1, res1) => {
        if (err1) throw err1;
        if (res1.isDirectory()) {
            readData(path.resolve(pathDir, "/index.html"), res);
        } else readData(pathDir, res);
    });
});
server.listen(8080, () => {
    console.log("localhost:8080");
});

你可能感兴趣的:(#,node.js,node.js,前端,后端)