NodeJs 入门
什么是 NodeJS?
简单的来说 Node.js 就是运行在服务器端的 Javascript。
Node.js 是一个基于 Chrome Javascript 运行时建立的一个平台。
Node.js 是一个事件驱动 I/O 服务端 Javascript 环境,基于 Google 的 V8 引擎,V8 引擎执行 Javascript 的速度非常快,性能非常好。
REPL(交互式解释器)
REPL -> Read Eval Print Loop, 表示一个电脑环境,类似系统的终端,可以直接输入命令
- R 读取用户输入,解析输入的 Javascript 数据解构并存储在内存中。
- E 执行输入的数据解构
- P 打印,输出结果
- L 循环,循环操作以上步骤直到用户两次按下
ctrl+c按钮退出。
$ node
> 1 + 4
5
REPL 命令
- ctrl + c 退出当前终端
- ctrl + c 按两次 退出 Node PEPL === .exit
- .help 列出使用命令
回调函数
Node.js 异步编程的直接就是回调。
// input.text
第一次创建input.text;
// main.js
// 同步,会阻塞
let fs = require("fs");
let data = fs.readFileSync("./input.text");
console.log(data.toString());
console.log("end");
// 输出结果
第一次创建input.text;
end;
// main.js
// 异步,不会阻塞
fs.readFile("./input.text", function(error, data) {
if (error) return console.log(error);
data && console.log(data.toString());
});
// 输出结果
end;
第一次创建input.text;
EventEmitter
events 模块只提供了一个对象: events.EventEmitter。
EventEmitter 的核心就是事件触发与事件监听功能的封装。
let events = require("events");
let eventEmitter = new events.EventEmitter();
// 监听notice 事件
eventEmitter.on("notice", function(args) {
console.log("监听了notice," + args);
});
// 触发notice事件
setTimeout(function() {
eventEmitter.emit("notice", "我被触发了!");
}, 500);
| 方法 | 描述 |
|---|---|
| addListener (event, listener) | 为指定事件添加一个监听器到监听器数组的尾部 |
| on (event, listener) | 为指定事件注册一个监听器,接收一个字符串 event 和 一个回调函数 |
| once (event, listener) | 为指定事件注册一个单词监听器,即监听器最多只会触发一次,触发后立刻解除该监听器 |
| removeListener (event, listener) | 移除指定事件的某个监听器,监听器必须是该事件已经注册过的监听器 |
| removeAllListeners ([event]) | 移除所有事件的所有监听器,如果指定事件,则移除指定事件下的所有监听器 |
| setMaxListeners (n) | 同一个事件,最大监听器数量,默认超过 10 个就会输出警告信息 |
| listeners (event) | 返回指定事件的监听器数组 |
| listenerCount (event) | 返回指定事件的监听器数量 |
| emit(event, [arg1], [arg2], [...]) | 按监听器的顺序执行执行每个监听器,如果事件有注册监听返回 true,否则返回 false |
let events = require("events");
let eventEmitter = new events.EventEmitter();
// 设置最大监听器的数量,比如notice3监听器超过3个,就会报错
eventEmitter.setMaxListeners(3);
eventEmitter.on("notice", function(args) {
console.log("监听了notice方法0000," + args);
});
eventEmitter.on("notice1", function(args) {
console.log("监听了notice方法1111," + args);
});
eventEmitter.on("notice2", function(args) {
console.log("监听了notice方法22222," + args);
});
// 为notice3 注册4个监听器
eventEmitter.on("notice3", function(args) {
console.log("监听了notice方法333333," + args);
});
eventEmitter.on("notice3", function(args) {
console.log("监听了notice方法333333------1," + args);
});
eventEmitter.on("notice3", function(args) {
console.log("监听了notice方法333333------2," + args);
});
eventEmitter.on("notice3", function(args) {
console.log("监听了notice方法333333------3," + args);
});
eventEmitter.on("notice4", function(...args) {
console.log(`传递的参数有: ${args}`);
});
setTimeout(function() {
eventEmitter.emit("notice2", "我被触发了!");
// 移除所有监听器
eventEmitter.removeAllListeners();
// 移除notice3下的所有监听器
eventEmitter.removeAllListeners("notice3", () => {
console.log("移除notice3下所有的监听器");
});
setTimeout(() => {
eventEmitter.emit("notice3", "我被触发了!");
eventEmitter.emit("notice2", "我被触发了!+1 ");
// 传递多个参数
eventEmitter.emit("notice4", 1, 2, 3, 4, 5, 6);
}, 1000);
}, 500);
// 输出 notice3事件下的监听器数组
console.log(eventEmitter.listeners("notice3"));
// 输出 notice3事件下的监听器数量
console.log(eventEmitter.listenerCount("notice3"));
Buffer 缓冲区
Javascript 语言自身只有字符串数据类型,没有二进制数据类型。
但在处理像 TCP 流或文件流时,必须使用到二进制数据。因此在 Node.js 中,定义了一个 Buffer 类,该类用来创建一个专门存放二进制数据的缓存区。
在 Node.js 中,Buffer 类是随 Node 内核一起发布的核心库。 Buffer 库为 Node.js 带来了一种存储原始数据的方法,可以让 Node.js 处理二进制数据,每当需要在 Node.js 中处理 I/O 操作中移动的数据时,就有可能使用 Buffer 库。
温馨提示
在 v6.0 之前创建 Buffer 对象直接使用 new Buffer()构造函数来创建对象实例,但是 Buffer 对内存的操作权限操作很大,可以直接捕获一些敏感信息。所以在 v6.0 以后,官方文档建议使用 Buffer.from() 去操作 Buffer 对象。
Buffer 与 字符编码
Buffer 实例一般用于表示编码字符的序列,比如 UTF-8、UCS2、Base64、或十六进制编码的数据。通过使用显式的字符编码,就可以在 Buffer 实例与普通的 Javascript 字符串之间进行相互转换。
目前支持的字符编码有:
- ascii: 仅支持 7 位 ASCII 数据。如果设置去掉高位的话,这种编码是非常快的
- utf8: 多字节编码的 Unicode 字符。许多网页和其他文档格式都使用 UTF-8
- utf16le: 2 或 4 个字节,小字节序编码的 Unicode 字符。支持代理对(U+10000 至 U+10FFFF)
- ucs2: utf16le 的别名
- base64: Base64 编码
- latin1: 一种把 Buffer 编码成一字节编码的字符串的方式
- binary: latin1 的别名
- hex: 将每个字节编码为两个十六进制字符
const buf = Buffer.from("runoob", "ascii");
console.log(buf.toString("hex"));
console.log(buf.toString("base64"));
Stream 流
Stream 是一个抽象接口,Node 中有很多对象实现了这个接口。例如,对 http 服务器发起请求的 request 对象就是一个 Stream,还有 stdout(标准输出)。
Node.js,Stream 有四种流类型:
Readable - 可读操作
Writable - 可写操作
Duplex - 可读可写操作
Transform - 操作被写入数据,然后读出结果
所有的 Stream 对象都是 EventEmitter 的实例。常用的事件有:
data - 当有数据可读时触发。
end - 没有更多的数据可读时触发。
error - 在接收和写入过程中发生错误时触发。
finish - 所有数据已被写入到底层系统时触发。
从流中读取数据
const fs = require("fs");
let data = "";
// 创建可读流
let readerStream = fs.createReadStream("./input.txt");
// 设置编码为utf8
readerStream.setEncoding("UTF-8");
// 处理流事件 data、end 、error、 finish
readerStream.on("data", function(chunk) {
data += chunk;
});
readerStream.on("end", function() {
console.log("end 输出结果:" + data);
});
readerStream.on("error", function(err) {
console.log("error 输出结果:" + err.stack);
});
console.log("程序执行完毕");
执行结果
程序执行完毕
end 输出结果:读取文件内容,这里是内容。
写入数据
const fs = require("fs");
let data = "这里是写入的内容";
// 创建一个可以写入的流,写入到文件 output.txt 中
let writeStream = fs.createWriteStream("./output.txt");
// 使用utf8写入数据
writeStream.write(data, "UTF-8");
// 标记文件末尾
writeStream.end();
// 处理流事件 data、end 、error、 finish
writeStream.on("end", function() {
console.log("end 输出结果:" + data);
});
writeStream.on("error", function(err) {
console.log("error 输出结果:" + err.stack);
});
writeStream.on("finish", function() {
console.log("写入完成");
});
console.log("程序执行完毕");
执行结果
程序执行完毕
写入完成
可以看到输出了个 output.txt 文件,文件中被写入了这里是写入的内容。
管道流
管道提供了一个输出流到输入流的机制。通常我们用于从一个流中获取数据并将数据传递到另外一个流中。相当于两个杯子中加加了个吸管,可以从高处流向低处。
操作一下,现在将通过读取一个文件内容写入到另外个文件中
const fs = require("fs");
// 创建一个可读流
const readStream = fs.createReadStream("./input.txt");
// 创建一个可写流
const writeStream = fs.createWriteStream("./output.txt");
// 管道读写操作
// 读取 input.txt 文件内容,并将内容写入到 output.txt 文件中
readStream.pipe(writeStream);
console.log("程序执行完毕");
执行结果
程序执行完毕
可以看到 output.txt 中被写入了读取文件内容,这里是内容。
链式流
链式是通过连接输出流到另外一个流并创建多个流操作链的机制。链式流一般用于管道操作。 相当于用多个吸管连接起来。
接下来我们就是用管道和链式来压缩和解压文件。
const fs = require("fs");
const zlib = require("zlib");
// 压缩 input.txt 文件为 input.txt.gz
fs.createReadStream("./input.txt")
.pipe(zlib.createGzip())
.pipe(fs.createWriteStream("input.txt.gz"));
console.log("文件压缩成功");
解压操作也是如此,先读取文件再写入。
模块系统
为了让 Node.js 的文件可以互相调用,Node.js 提供了简单的模块系统。
一个 Node.js 文件就是一个模块。
创建模块
// main.js
let hello = require("./hello");
hello.world();
// hello.js
exports.world = function() {
console.log("Hello Nodejs");
};
Node.js 提供了 exports 和 require 两个对象,其中 exports 是模块公开的接口,require 用于从外部获取一个模块的接口,即所获取模块的 exports 对象。
hello.js 通过 exports 对象把 world 作为模块的访问接口,直接可以访问 hello.js 中 exports 对象的成员函数了。
也可以把对象封装到模块中,如
// hello.js
function Hello() {
let name;
this.setName = function(opts) {
name = opts;
};
this.sayHello = function() {
console.log("Hello " + name);
};
}
module.exports = Hello;
// main.js
let Hello = require("./hello");
let hello = new Hello();
hello.setName("kk");
hello.sayHello();
模块接口的唯一变化是使用了 module.exports = Hello; 代替了 exports.world = function(){}
在外部引用该模块时,其接口对象就是要输出的 Hello 对象本身,而不是原先的 exports
exports 与 module.exports 区别
exports 其实是 module.exports 的简写, exports === module.exports === {}, 都是指向同一个内存地址。
- require 引入的其实是module.exports导出的, exports 只是 module.exports 决定导出一个对象时的快捷方式。
- 一个模块文件中可以有多个 exports 输出,但是只能有一个 module.exports 输出
function Hello() {
var name;
this.setName = function(argName) {
name = argName;
};
this.sayHello = function() {
console.log("Hello " + name);
};
}
function Test() {
console.log("test");
}
// 返回的是模块对象本身,返回的是一个类
module.exports = Hello;
// 导出多个
module.exports = {
Hello,
Test
};
// 返回的是模块函数
exports.Hello = Hello;
// 导出多个
exports.Test = Test;
扩展一下: 区分 ES6 Module
- 模块引入: import
- 模块导出: export || export default
- 在一个文件或模块中,export 可以有多个,export default 只能向外暴露一次
- 通过 export 方式导出,是一个对象,需要解构。export default, 实际上是输出一个叫 default 的变量,用于储存。
- Node 不支持 ES6 module 特性,需要用 babel 编译
// export
export const name = "kk";
export function fun() {
console.log("123");
}
import { name, fun } from "./export";
console.log(name); // 'kk'
console.log(fun); // fun: [Function: fun]
fun(); // '123'
// export default
function fun() {
console.log("123");
}
export default fun;
// 系统允许为它取任意变量名
import fun from "./export-default";
console.log(fun); // fun: [Function: fun]
fun(); // '123'
再看看这些
// test.js
const options = {
name: "kk",
age: 16
};
// module.exports 导出
module.exports = options;
// main.js
const opt = require("./test.js");
// exports.default 导出
exports.default = options;
const opt = require("./test.js").default;
// export default 导出
export default options;
const opt = require("./test.js").default;
// export 导出
export const options = {
name: "kk",
age: 16
};
// 需要解构
const { options } = require("./test.js");
| Node | 浏览器 | |
|---|---|---|
| 模块规范 | CommonJS | ES6 |
| 导出 | modules.exports, exports | export, export default |
| 导入 | require | import, require |
服务端模块
Node.js 中自带一个叫做 http 的模块。
const http = require('http');
http.createServer(...);
函数
跟函数式编程类似,将函数作为形参。可以先定义一个函数,再进行传递。也可以在传递参数的地方直接定义函数。
function say(value) {
console.log(value);
}
function execute(fun, value) {
fun(value);
}
execute(say, "Hello Nodejs");
用函数方式启动 HTTP 服务器
// 普通方式
const http = require("http");
http
.createServer(function(req, resp) {
resp.writeHead(200, { "Content-type": "text/plan" });
resp.write("Hello Nodejs");
resp.end();
})
.listen(8888);
// 通过传递函数
function onRequest(req, resp) {
resp.writeHead(200, { "Content-type": "text/plan" });
resp.write("Hello Nodejs");
resp.end();
}
http.createServer(onRequest).listen(8888);
路由
为路由提供请求的 URL 和 其他需要的 GET 及 POST 参数,随后路由需要根据这些数据来执行相应的代码。
// index.js
let router = require("./router");
let server = require("./server");
server.start(router.route);
// router.js
function route(pathname, response) {
// console.log('About to route a request for ' + pathname);
if (pathname === "/") {
response.writeHead("200", { "Content-Type": "text/plain" });
response.write("200, Hello Nodejs");
response.end();
} else if (pathname === "/about") {
response.end("about");
} else {
response.end("404");
}
}
exports.route = route;
// server.js
let http = require("http");
let url = require("url");
function start(route) {
function onRequest(request, response) {
// console.log(url.parse(request.url));
let pathname = url.parse(request.url).pathname;
// console.log(`Request for ${pathname} received.`);
route(pathname, response);
}
http.createServer(onRequest).listen(8900);
console.log("服务启动");
}
exports.start = start;
执行 index.js 文件,就可以看了。当路由切换到 about, 页面会输出 about。
全局对象
Javascript 中有一个特殊的对象,称为全局对象(Global Object),它及其所有属性都可以在程序的任何地方访问,即全局变量。
在浏览器 Javascript 中,window、self 是全局对象,而在 Node.js 中全局对象是 global, 所有全局变量(即除了 global 本身以外)都是 global 对象的属性。
全局对象与全局变量
global 最根本的作用是作为全局变量的宿主。
在 Node.js 中你不可能在最外层定义变量,因为所有用户代码都是属于当前模块的,而模块本身不是最外层上下文。
注意
最好不要使用 var 定义变量,避免引入全局变量。因为群居变量会污染命名空间,提高代码的耦合风险!
__filename
__filename 表示当前正在执行的脚本的文件名。它将输出文件所在位置的绝对路径,且和命令行参数所指定的文件名不一定相同。 如果在模块中,返回的值是模块文件的路径。
console.log(__filename);
// /Users/kk/kk/project/learn-notes/src/node/main.js
__dirname
__dirname 表示当前执行脚本所在的目录。
console.log(__dirname);
// /Users/kk/kk/project/learn-notes/src/node/
setTimeout(cb, ms) && clearTimeout(t)
全局函数在指定的毫秒(ms)数后执行指定函数(cb)
setTimeout() 只执行一次指定函数。 返回一个代表定时器的句柄值。
clearTimeout(t) 全局函数用于停止一个之前通过 setTimeout() 创建的定时器。
用法跟跟 js 相同
let t = setTimeout(function() {
console.log("Hello Nodejs");
}, 200);
clearTimeout(t);
setInterval(cb, ms)
setInterval(cb, ms) 全局函数在指定的毫秒数后执行指定函数,返回一个代表定时器的句柄值。
可以使用 clearInterval(t) 函数来清除定时器。
setInterval() 会不停的调用函数,直到 clearInterval() 被调用或者窗口被关闭。
let t = setInterval(function() {
console.log("Hello Nodejs");
}, 200);
以上程序每隔两秒就会输出一次"Hello Nodejs",且会永久执行下去,直到中断它。(ctrl + c) 或者调用 clearInterval()
let count = 0;
const t = setInterval(function() {
if (count === 10) {
clearInterval(t);
} else {
count++;
console.log("Hello Nodejs");
}
}, 200);
console
console 用于控制台标准输出,是调试工具,后面逐渐成为浏览器的实施标准。
常用方法:
| 方法 | 描述 |
|---|---|
| log([data][,...]) | 向标准输出流打印字符并以换行符结束 |
| info([data][,...]) | 输出消息性信息 |
| error([data][,...]) | 输出错误消息 |
| warn([data][,...]) | 输出警告信息 |
| dir(obj[,options]) | 用来对一个对象进行检查,并以易于阅读和打印的格式显示 |
| time(label) | 输出时间,表示计时开始 |
| timeEnd(label) | 输出结束时间,表示计时结束 |
| trace(message[,...]) | 当前执行的代码在堆栈中的调用路径 |
| assert(value[,message][,...]) | 用于判断某个表达式或变量是否为真,接收两个参数,第一个参数是表达式,第二个参数是字符串。只有当第一个参数为 false,才会输出第二个参数,否则不会有任何结果。 |
// 这两个方法均使用一个参数,参数值可以为任何字符串,但是这两个方法所使用的参数字符串必须相同,才能正确地统计出开始时间与结束时间之间所经过的毫秒数。
console.time("small loop");
for (let i = 0; i < 1000; i++) {
console.log(i);
}
console.timeEnd("small loop");
// small loop: 47.735ms
function foo() {
function bar() {
console.trace();
}
bar();
}
foo();
console.assert(1 + 1 > 2, "false, 1+1不大于2");
console.assert(false, "the word is %s", "foo");
const errorMsg = "the # is not even";
for (let number = 2; number <= 5; number += 1) {
console.log("the # is " + number);
console.assert(number % 2 === 0, { number, errorMsg });
}
process
process 是一个全局变量,即 global 对象的属性。
用于描述当前 Node.js 进程状态的对象,提供了一个与操作系统的简单接口。
| 事件 | 描述 |
|---|---|
| exit | 当进程准备退出时触发 |
| beforeExit | 当 node 清空事件循环,并且没有其他安排时触发这个事件。 |
| uncaughtException | 当一个异常冒泡回到事件循环,触发这个事件。这个给异常添加了监视器,默认的操作就不会发生。 |
| Signal | 当进程接收到信息时就触发。 |
process.on("exit", function(code) {
// 以下代码永远不会执行
setTimeout(function() {
console.log("该代码不会执行");
}, 0);
console.log("退出状态码: " + code);
});
console.log("程序执行完毕!");
程序执行完毕!
退出状态码: 0
一些常用的属性
// 输出到终端
process.stdout.write("Hello Nodejs" + "\n");
// 通过参数读取
console.log(process.argv);
process.argv.forEach(function(item, index, array) {
console.log(index + ":" + item);
});
// 获取执行路径
console.log(process.execPath);
// 输出当前目录
console.log(process.cwd());
// 平台信息
console.log(process.platform);
// 版本
console.log(process.version);
// 版本信息
console.log(process.versions);
// 输出内存使用情况
console.log(process.memoryUsage());
常用工具 util
util 是 Nodejs 的核心模块,提供常用函数的集合,用于弥补核心 Javascript 的功能过于精简的不足。
const util = require("util");
util.callbackify
util.callbackify(original) 将 async 移步函数(或者一个返回值为 promise 的函数),转换成异常优先的回调等个的函数。如(err, value) => ... 回调作为最后一个参数。
// 异步函数
const util = require("util");
async function fn() {
return "Hello Nodejs";
}
const callbackFunction = util.callbackify(fn);
callbackFunction((err, res) => {
if (err) throw err;
console.log(res);
});
// Promise
function fn() {
return Promise.resolve("Hello Nodejs");
// return Promise.reject('错误信息');
}
回调函数是异步执行的,并且有异常堆栈错误追踪。如果回调函数抛出一个异常,进程会触发一个'uncaughtException' 异常。如果没有被捕获,那么进程将会退出。 另外,null 在回调函数中作为一个参数有特殊的意义,如果回调函数的首个参数为 Promise 拒绝的原因且带有返回值,且值可以转换成布尔值 false, 这个值会被封装在 Error 对象里,可以通过 reason 属性获取。
function fn() {
return Promise.reject(null);
}
const callbackFunction = util.callbackify(fn);
callbackFunction((err, res) => {
// 当 Promise 被以 `null` 拒绝时,它被包装为 Error 并且原始值存储在 `reason` 中。
if (err && err.hasOwnProperty("reason") && err.reason === null) {
console.log(err);
}
});
// 输出err错误信息
util.inherits
util.inherits(constructor, superConstructor) 是一个实现对象间原型继承的函数。
Javascript 的面向对象特性是基于原型的,与常见的基于类的不同。Javascript 没有提供对象继承的语言级别特性,而是通过原型复制来实现的。
function Base() {
this.name = "Base";
this.base = 2020;
this.sayHello = function() {
console.log("Hello " + this.name);
};
}
Base.prototype.showName = function() {
console.log(this.name);
};
Base.prototype.diyString = "自定义属性";
function Sub() {
this.name = "Sub";
}
// 定义一个基础对象Base 和 一个继承自Base的Sub
util.inherits(Sub, Base);
let objBase = new Base();
console.log(objBase.name);
console.log(objBase.base);
console.log(objBase.sayHello());
console.log(objBase.showName());
console.log(objBase.diyString);
console.log(objBase);
let objSub = new Sub();
console.log(objSub.name);
console.log(objSub.base);
// 去掉这行注释,将会报错,Sub 中并没有 sayHello 函数
// console.log(objSub.sayHello());
console.log(objSub.showName());
console.log(objSub.diyString);
console.log(objSub);
TIP
Sub 仅仅继承了 Base 在原型中定义的函数,而构造函数内部创造的 base 属性和 sayHello 函数都没有被 Sub 继承
util.inherits() 只会继承原型中的属性。
util.inspect
util.inspect(object, [showHidden], [depth], [colors]) 是一个将任意对象转换成字符串的方法。通常用于调试和错误的输出。
- object, 即要转换的对象
- showHidden, 可选参数,为 true,表示会输出更多隐藏信息
- depth,表示最大递归层数,默认为 2,指定为 null 表示将不限递归层数完整遍历对象。
- colors, 为 true, 表示输出格式为 ANSI 颜色编码
util.inspect() 并不会简单地直接把对象转换成字符串,即使该对象定义了 toString 方法也不会调用。
console.log (util.inspect(objBase));
console.log (util.inspect(objBase, true));
// 输出结果
Base { name: 'Base', base: 2020, sayHello: [Function] }
Base {
name: 'Base',
base: 2020,
sayHello:
{ [Function]
[length]: 0,
[name]: '',
[arguments]: null,
[caller]: null,
[prototype]: { [constructor]: [Circular] } } }
util.types.isRegExp(object)
如果形参 object 是一个正则表达式,则返回 true,否则返回 false。
util.isRegExp(object) v4.0.0 已被弃用
console.log(util.types.isRegExp(/some regexp/));
console.log(util.types.isRegExp(new RegExp("test regexp")));
console.log(util.types.isRegExp({}));
// 输出结果
true;
true;
false;
util.types.isDate(object)
如果形参 object 是一个日期,则返回 true,否则返回 false。 只支持 Date 对象。
util.isDate(object) v4.0.0 已被弃用
console.log(util.types.isDate(new Date()));
console.log(util.types.isDate(Date()));
console.log(util.types.isDate({}));
console.log(util.types.isDate("2020/07/02"));
console.log(util.types.isDate("1593619200000"));
// 输出结果
true;
false;
false;
false;
false;
util.isArray(object) 弃用
如果形参 object 是一个数组,则返回 true,否则返回 false。
v4.0.0 弃用,替代方法 Array.isArray(object)
console.log(Array.isArray([]));
console.log(Array.isArray(new Array()));
console.log(Array.isArray({}));
console.log(Array.isArray("123"));
console.log(Array.isArray(123));
console.log(Array.isArray(true));
// 输出结果
true;
true;
false;
false;
false;
false;
文件系统
Node.js 提供一组类似 UNIX (POSIX)标准的文件操作 API。 fs 模块。
const fs = require("fs");
异步 && 同步
fs 模块中的方法均有异步和同步版本,如读取文件内容的函数,异步 -> fs.readFile() ,同步 -> fs.readFileSync().
异步方法函数,最后一个参数为回调函数 cb, 回调函数的第一个参数包含了错误信息 error。
建议大家都使用异步方法,比起同步,异步性能更高,速度更快,不会阻塞。
let fs = require('fs');
// 异步读取文件
fs.readFile('./input1.txt', (error, data) => {
if (error) {
console.log(error);
return;
}
console.log(data.toString());
});
console.log('程序执行完毕');
// 输出结果
程序执行完毕
读取文件内容,这里是内容。
// 同步读取文件
let data = fs.readFileSync('./input.txt', 'utf-8');
console.log(data.toString());
console.log('程序执行完毕');
// 输出结果
读取文件内容,这里是内容。
程序执行完毕
打开文件
以下为异步模式下打开文件的语法格式:
fs.open(path, flags[, mode], callback);
| 参数 | 描述 |
|---|---|
| path | 文件路径 |
| flags | 文件打开的行为 |
| mode | 文件模式(权限) |
| callback | 回调函数,带有两个参数 callback(error, fd) |
| Flag | 描述 |
|---|---|
| r | 以读取模式打开文件,如果文件不存在抛出异常 |
| r+ | 以读写模式打开文件,如果文件不存在抛出异常 |
| rs | 以同步的方式读取文件 |
| rs+ | 以同步的方式读取和写入文件 |
| w | 以写入模式打开文件,如果文件不存在则创建 |
| wx | 类似'w', 但是如果文件路径存在,则文件读写失败 |
| w+ | 以读写模式打开文件,如果文件不存在则创建 |
| wx+ | 类似'w+', 但是如果文件路径存在,则文件读写失败 |
| a | 以追加模式打开文件,如果文件不存在则创建 |
| ax | 类似'a', 但是如果文件路径存在,则文件追加失败 |
| a+ | 以读取追加模式打开文件,如果文件不存在则创建 |
| aw+ | 类似'a+',但是如果文件路径存在,则文件追加失败 |
// 异步打开文件
console.log("准备打开文件");
fs.open("./input.txt", "w+", function(err, fd) {
if (err) {
return console.log(err);
}
// 文件描述符
console.log(fd);
console.log("文件打开成功");
});
// 输出结果
准备打开文件;
20;
文件打开成功;
写入文件
以下为异步模式下打开文件的语法格式:
fs.writeFile(file, data[, options], callback)
callback 只包含 error, callback(error)
console.log('准备写入文件');
fs.writeFile('./input.txt', '我是通过 fs.writeFile() 写入的内容', function(err) {
if (err) {
return console.log(err);
}
console.log('数据写入成功!');
console.log('--------分割线---------');
fs.readFile('./input.txt', function(error, data) {
console.log(data.toString());
})
});
// 输出结果
准备写入文件
数据写入成功!
--------分割线---------
我是通过 fs.writeFile() 写入的内容
创建目录
fs.mkdir(path[, options], callback)
option 参数可选
- recursive 是否以递归的方式创建目录,默认为 false
- mode 设置目录权限,默认为 0777
fs.mkdir("./test/", function(error) {
if (error) return console.log(error);
console.log("目录创建成功!");
});
删除目录
fs.rmdir(path, callback);
fs.rmdir("./test/", function(error) {
if (error) return console.log(error);
console.log("目录删除成功!");
});
删除文件
fs.unlink(path, callback);
fs.unlink("./input.txt.gz", function(error) {
if (error) return console.log(error);
console.log("文件删除成功!");
});
工具模块
| 模块名 | 描述 |
|---|---|
| os | 提供基本的系统操作函数 |
| path | 提供了处理和转换文件路径的工具 |
| net | 用于底层的网络通信。提供了服务端和客户端的操作 |
| dns | 用于解析域名 |
| domain | 简化异步代码的异常操作,可以捕捉处理 try catch 无法捕捉的 |