Node是对ES标准的一种实现,Node也是JS引擎。
通过Node可以使JS代码在服务端执行。
Node的服务器是单线程的,但是在后台拥有一个I/O线程池。
Node处理速度快,适合页面渲染。
1、Web服务API,比如rest
2、实时多人游戏
3、后端的Web服务,例如跨域、服务器端的请求
4、基于Web的应用
5、多客户端的通信,如即时通信
1、使用Win+R打开命令行窗口
2、输入cd+目录名,进入文件所在目录
3、node + 空格 + 所需执行的js文件名
快捷方式:在所需执行文件的文件夹上方输入cmd,在执行第三步操作。
- 在Node中,一个js文件就是一个模块。
- 在Node中,每一个js文件中的js代码都是独立运行在一个函数中的,而不是全局作用域,所以一个模块中的变量和函数在其他模块中无法访问。
CommonJS规范
- CommonJS规范的提出,主要是为了弥补当前JavaScript没有标准的缺陷。
- CommonJS规范为JS指定了一个美好的愿景,希望JS能够在任何地方运行。
- CommonJS对模块的定义十分简单:模块引用、模块定义、模块标识。
在Node中,通过require()函数来引入外部的模块。
require()中可以传递一个文件的路径作为参数,node将会自动根据该路径引入外部模块。
这里路径如果使用相对路径,必须以.或者..开头。
require("./02.moudle.js");
使用require()引入模块以后,该函数会返回一个对象,这个对象代表的是引入的模块。
可以通过exports来向外暴露变量和方法
只需要将需要暴露给外部的变量或方法设置为exports的属性即可。
console.log("我是一个模块,我是01.module");
exports.x = "我是01.module.js中的x";
exports.y = "我是01.module.js中的y";
exports.fn = function() {
};
var md = require("./01.module.js");
console.log(md.x);
console.log(md.y);
console.log(md.fn);
引用案例:定义一个模块match,在该模块中提供两种方法:
add(a,b);求两个数的和,mul(a,b);求两个数的积
//02.module.js
var math = require("./03.math");
console.log(math.add(123, 456)); //579
//03.math.js
exports.add = function(a, b) {
return a + b;
}
exports.mul = function(a, b) {
return a * b;
}
在Node中,模块分为三类:
① 内建模块:底层由C++编写的模块
② 核心模块:由Node引擎提供的模块
核心模块的标识就是模块的名字
示例:var fs = require("fs");
③ 文件模块:由用户自己创建的模块
文件模块的标识就是文件的路径
(绝对路径,一般来说是相对路径。相对 路径使用.或者..开头)
—路径分析
—文件定位
—编译执行
在Node中有一个全局对象global,它的作用和网页中的window类似。
在全局中创建的变量都会作为global的属性保存。
在全局中创建的函数都会作为global的方法保存。
- 当Node在执行模块中的代码时,会首先在代码的最顶部,添加如下代码:
function(exports,require,module,__filename,__dirname){
- 在代码的最底部,添加如下代码: }
- 实际上模块中的代码都是包装在一个函数中执行的,并且在函数执行时,同时传递进了5个实参。
① exports:该对象用来将变量或函数暴露到外部
② require:函数,用来引入外部模块
③ module:module代表的当前模块本身,exports是module的属性
既可以使用exports导出,也可以使用module.exports导出
④ __filename:当前模块的完整路径
⑤ __dirname:当前模块所在文件夹完整路径
exports和module.exports:
① 通过exports只能使用.的方式来向外暴露内部变量
exports.xxx = xxx
② 而module.exports既可以通过.的方式,也可以直接赋值
module.exports.xxx = xxxx
module.exports = { }
CommonJS的包规范允许我们将一组相关的模块组合到一起,形成一组完整的工具。
CommonJS的包规范由包结构和包描述文件两个部分组成。
—package.json:描述文件
—bin:可执行二进制文件
—lib:js代码
—doc:文档
—test:单元测试
name、description、version、keywords、maintainers、contributors、bugs、licenses、
repositories、dependencies、homepage、os、cpu、engine、builtin、direcotries、
implements、scripts、author、bin、main、devDependencies。
- 通过NPM下载的包都放到node_modules文件夹中
- 通过NPM下载的包,直接通过包名引入即可。
- Node在使用模块名字来引入模块时,首先在当前目录的node_modules中寻找是否含有该模块:
① 如果有则直接使用,如果没有则去上一级目录的node_modules中寻找
② 如果有则直接使用,如果没有则再去上一级目录寻找,直到找到为止
③ 直到找到磁盘的根目录,如果依然没有,则报错
① npm -v :查看版本
② npm:帮助说明
③ npm version:查看所有模块的版本
④ npm search 包名:搜索模块包
⑤ npm install / i 包名:在当前目录安装包
⑥ npm install 包名 + -g:全局模式安装包(全局安装的包一般都是一些工具)
⑦ npm remove 包名:删除包
⑧ npm install 包名 --save:安装包并添加到依赖中
⑨ npm install :下载当前项目所依赖的包
⑩ npm install 文件路径:从本地安装
npm install 包名 -registry=地址:从镜像源安装
npm config set registry 地址:设置镜像源
从结构上看Buffer非常像一个数组,它的元素为16进制的两位数。
数组中不能存储二进制的文件,而buffer就专门用来存储二进制数据。
使用buffer不需要引入模块,直接使用即可。
实际上一个元素就表示内存中的一个字节。
实际上Buffer中的内存不是通过JavaScript分配的,而是在底层通过C++申请的。
也就是我们可以直接通过Buffer来创建内存中的空间。
var str = "hello world";
//将一个字符串保存到buffer中
var buf = Buffer.from(str);
console.log(buf); //
console.log(buf.length); //11 占用内存的大小 表示占用内存11个字节
console.log(str.length); //11 获取的是字符串的长度
Buffer中存储的都是二进制数据,但是是以十六进制的形式来显示。
buffer中的每一个元素的范围是从00—ff (00000000—11111111)
计算机中,一个0或者一个1,称为1位(bit)
8bit = 1byte(字节),字节是数据传输最小的单位
buffer中的一个元素,占用内存一个字节。
英文占用内存中的一个字节,汉字占用内存三个字节
- 1024byte = 1kb
- 1024kb = 1mb
- 1024mb=1gb
- 1024gb=1tb
//buffer的构造函数都是不推荐使用的
var buf2 = new Buffer(10); //10个字节的buffer
console.log(buf2.length);
Buffer的大小一旦确定,则不能修改。
Buffer实际上是对底层内存的直接操作。
//创建一个10字节的buffer
var buf2 = Buffer.alloc(10);
buf2[0] = 88;
buf2[1] = 255;
buf2[2] = 0xaa;
buf2[10] = 15;
console.log(buf2); //
//只要数字在控制台或页面中输出一定是10进制
console.log(buf2[2]); //170
console.log(buf2[2].toString(16)); //aa
Buffer.allocUnsafe(size) 创建一个指定大小的buffer,但是buffer中可能含有敏感数据.
var buf3 = Buffer.allocUnsafe(10);
console.log(buf3); //
Buffer.from(str):将一个字符串转化为buffer
Buffer.alloc(size):创建一个指定大小的buffer
Buffer.allocUnsafe(size):创建一个指定大小的buffer
buf.toString():将缓冲区的数据转化为字符串
var buf4 = Buffer.from("我是一段文本数据");
console.log(buf4.toString());
文件系统(File System):通过Node来操作系统中的文件。
使用文件系统,需要先引入fs模块,fs是核心模块,直接引入,不需要下载。
const fs = require("fs");
fs模块中所有的操作都有两种形式可供选择同步和异步。
fs.openSync*(path,flags[, mode])
- path:要打开文件的路径
- flags:打开文件要做的操作的类型 r-只读的 w-可写的
- mode 设置文件的操作权限,一般不传
fs.writeSync(fd,string[,position[,encoding]])
- fd:文件的描述符,传递要写入文件的描述符
- string:要写入的内容
- position:写入的起始位置
- encoding:写入的编码,默认utf-8
fs.closeSync(fd)
- fd:要关闭的文件的描述符
var fs = require("fs");
//1、打开文件
var fd = fs.openSync("hello.txt","w");
//2、向文件中写入内容
fd.writeSync(fd,"今天晚上吃什么呢???",2);
//3、保存并关闭文件
fd.closeSync(fd);
fs.open(path, flags[, mode], callback)
- callback:不能省略,是回调函数
- 用来打开一个文件
- 异步调用的方法,结果都是通过回调函数的参数返回的。
- 回调函数有两个参数:
① err 错误对象:如果没有错误则为null
② fd 文件的描述
fs.write(fd,string[,position[,encoding]],callback)
- 用来异步写入一个文件
fs.close(fd,callback)
- 用来关闭文件的
- 异步的close(2)。完成回调只有一个可能的异常参数
/*异步文件写入*/
// (1)打开文件
//fs.open(path, flags[, mode], callback)
var fs = require("fs");
//异步调用的方法,结果都是通过回调函数的参数返回的
fs.open("hello2.txt", "w", function(err, fd) {
//判断是否出错
if (!err) {
//如果没有出错,则对文件进行写入操作
// (2)向文件中写入内容
fs.write(fd, "这是异步写入的内容", function(err) {
if (!err) {
console.log("写入成功~~~");
}
//(3)保存并关闭文件
fs.close(fd, function(err) {
if (!err) {
console.log("文件已关闭~~~");
}
})
});
} else {
console.log(err);
}
})
同步:fs.writeFileSync(file,data[,options],callback)
异步:fs.writeFile(file,data[,options])
- file:要操作的文件路径
- data:要写入的数据
- option:选项,可以对写入进行设置(可省略)
- callback:写入完成以后执行的函数
- flag: r(只读) w(可写) a(追加)
var fs = require("fs");
//此时的hellow3.txt是相对路径
fs.writeFile("hello3.txt", "这是通过writeFile写入的内容", { flag: "a" }, function(err) {
if (!err) {
console.log("写入成功");
} else {
console.log(err);
}
});
//绝对路径的使用
使用前:C:\Users\lilichao\Desktop\hello.txt
使用后:C:\\Users\\lilichao\\Desktop\\hello.txt
同步:fs.readFile(path[,options],callback)
异步:fs.readFile(path[,options])
- path:要读取文件的路径
- options:读取的选项
- callback回调函数:通过回调函数将读取到的内容返回(err,data)
- err:错误对象
- data:读取到的数据,会返回一个Buffer,可转换成字符串
//简单文件读取
var fs = require("fs");
fs.readFile("hello3.txt", function(err, data) {
if (!err) {
// console.log(data);
// 将data写入到文件中
fs.writeFile("hello.jpg", data, function(err) {
if (!err) {
console.log("文件写入成功");
}
})
}
})
同步、异步、简单文件的写入都不适合大文件的写入,性能较差,容易导致内存溢出。
往一个文件中写入大量数据时,最好的方法之一是使用流。
流式文件可持续写入。
fs.createWriteStream(path[, options]) 可以用来创建一个可写流
path:文件路径
options:配置的参数,可省略不写
var fs = require("fs");
var ws = fs.createWriteStream("hello4.txt");
//可以通过监听流的open的close事件来监听流的打开和关闭
//打开流
//open只会触发一次,是一次性事件
//on(事件字符串,回调函数) :可以为对象绑定一个事件
//once(事件字符串,回调函数):可以为对象绑定一个一次性的事件,该事件将会在触发一次以后自动失效
ws.once("open", function() {
console.log("流打开了~~~");
});
ws.once("close", function() {
console.log("流关闭了~~~");
})
//通过ws向文件中输入内容,可持续写入
ws.write("通过可写流,写入文件的内容");
ws.write("今天晚上吃什么?");
ws.write("甜皮鸭");
ws.write("稀饭");
//关闭流
ws.close();
流式文件的读取也使用于一些比较大的文件,可以分多次将文件读取到内存中。
/流式文件读取
// 流式文件的读取也使用于一些比较大的文件,可以分多次将文件读取到内存中
var fs = require("fs");
//创建一个可读流
var rs = fs.createReadStream("E:/前端软件/学习操作/8.Node.js/03-文件系统/草东-还愿.mp3");
//创建一个可写流
var ws = fs.createWriteStream("a.mp3");
//监听流的开启和关闭
rs.once("open", function() {
console.log("可读流打开了~~");
});
rs.once("close", function() {
console.log("可读流关闭了~~~");
//数据读取完毕,关闭可写流
ws.close();
});
ws.once("open", function() {
console.log("可写流打开了~~~");
});
ws.once("close", function() {
console.log("可写流关闭了~~~");
})
//如果要读取一个可读流中的数据,必须要为可读流绑定一个data事件,data事件绑定完毕,它会自动开始读取数据
rs.on("data", function(data) {
//console.log(data);
//将读取到的数据,写入到可写流中
ws.write(data);
});
pipe()可以将可读流中的内容,直接输出到可写流中。
var fs = require("fs");
//创建一个可读流
var rs = fs.createReadStream("E:/前端软件/学习操作/8.Node.js/03-文件系统/草东-还愿.mp3");
//创建一个可写流
var ws = fs.createWriteStream("b.mp3");
//pipe()可以将可读流中的内容,直接输出到可写流中
rs.pipe(ws);
1、验证路径是否存在:fs.existsSync(path)
2、获取文件信息:fs.stat(path,callback)
fs.statSync(path)
它会给我们返回一个对象,这个对象中保存了当前对象状态的相关信息
3、删除文件:fs.unlink(path,callback)
fs .unlinkSync(path)
4、列出文件:fs.readdir(path,[,options],callback)
fs.readdirSync(path,[,options])
5、截断文件:fs.truncate(path,len,callback)
fs.truncateSync(path,len)
将文件修改为指定的大小
6、建立目录:fs.mkdir(path,[,mode],callback)
fs.mkdirSync(path,[,mode])
7、对文件进行重命名:fs.rename(oldPath,newPath,callback)
fs.renameSync(oldPath,newPath)
参数:oldPath:旧的路径
newPath:新的路径
8、监视文件的修改:fs.watchFile(filename[,options],listener)
参数:filename:要监视的文件的名字
options:配置选项
listener:回调函数,当文件发送变化时,回调函数会执行
var fs = require("fs");
//一、检查一个文件是否存在
// fs.existsSync(path)
var isExists = fs.existsSync("a.mp3");
console.log(isExists);
//二、获取文件的状态:fs.stat(path,callback)
// fs.statSync(path)
fs.stat("a.mp3", function(err, stat) {
//size:文件的大小
//isFile():是否是一个文件
//isDirectory():是否是一个文件夹
console.log(stat.size);
})
//三、删除文件:fs.unlink(path,callback)
// fs.unlinkSync(path)
fs.unlinkSync("a.mp3");
//四、列出文件 fs.readdir(path,[,options],callback)
// fs.readdirSync(path,[,options])
// 读取一个目录的目录结构
//files是一个字符串的数组,每一个元素就是一个文件夹,或文件的名字
fs.readdir(".", function(err, files) {
if (!err) {
console.log(files);
}
});
//五、截断文件 fs.truncate(path,len,callback)
// fs.truncateSync(path,len)
// 将文件修改为指定的大小
fs.truncateSync("hello2.txt", 14);
//六、建立目录
// fs.mkdir(path,[,mode],callback)
// fs.mkdirSync(path,[,mode])
fs.mkdirSync("abc");
//七、对文件进行重命名:fs.rename(oldPath,newPath,callback)
// fs.renameSync(oldPath,newPath)
// 参数:oldPath:旧的路径
// newPath:新的路径
fs.rename("hello.txt", "笔记本.txt", function(err) {
console.log("修改成功");
});
// 八、监视文件的修改:fs.watchFile(filename[,options],listener)
// 参数:filename:要监视的文件的名字
// options:配置选项
// listener:回调函数,当文件发送变化时,回调函数会执行
// 在回调函数中会有两个参数:cur 当前文件的状态
// prev 修改前文件的状态
// 这两个对象都是stats对象
fs.watchFile("hello2.txt", function(curr, prev) {
console.log("修改前文件大小:" + prev.size);
console.log("修改后文件大小:" + curr.size);
})