nodejs学习
预备知识
- 在Node中一个js文件就是一个模块
- 每个js文件中的变量和函数都是包含在一个无形的函数中的,在别的js文件中要想访问这些变量和函数,必须通过exports
a.js
exports.x = a;
exports.fn = function () {}
js.js
var a = require("./a.js");
console.log(a.x);
- node自带交互式解析器(REPL-- read读取、eval求值、print输出、loop循坏)
作用:在cmd中输入node.exe便可进入REPL。REPL可以用来读取执行javaScript语句,类似电脑的cmd
PS: 在cmd中输入node a.js便可以直接运行整个js文件
异步与同步
- 同步实现文件读取
var fs = require('fs');
var data = fs.readFileSync('a.js','utf-8');
console.log(data);
console.log("程序执行结束!");
- 异步实现文件读取
var fs = require('fs');
fs.readFile('./a.js',function(err,data){
if(err) return console.log(err);
console.log(data.toString());
});
console.log("程序执行结束!");
js模块揭秘
- 每个node模块其实都是包含在一个函数中
- 当node在执行模块的代码时,它会首先在代码的最顶部添加如下代码:
function (exports,require,module,_filename,_dirname){
在代码的最底部添加如下代码
}
所以实际上模块中的代码都是包含在一个函数中执行的,并且在函数执行时,同时传递了5个实参
exports
-该对象用来将变量或者函数暴露到外部
require
-函数,用来引入外部的模块
module
-代表的是当前模块本身,exports实际就是module的一个属性
console(exports==module.exports) // true
__filename
-D:\learn\nodejs\node\a.js
-表示当前文件的完整路径
__dirname
-D:\learn\nodejs\node
-表示当前文件所在文件夹的完整路径
module.exports和exports的区别
- 变量暴露的区别
module.exports可以通过以下方式暴露变量name 和 age
module.exports = {
'name': 'zhouzhou',
'age': '15'
}
而exports不能通过以下方式暴露name 和 age
exports = {
'name': 'zhouzhou',
'age': '15'
} - con 总结
模块向外暴露的变量总是module.exports的一个属性,而不是exports的一个属性,所以当exports跟module.exports
指向不同的地址时,暴露的变量还是以module.exports拥有的属性或者方法为准
package包
package
- "包"是规范化的"模块"
组成
- 包结构
-package.json 描述文件
-bin 可执行二进制文件
-lib js代码
-doc 文档
-test 单元测试
只有package.json是必需的 - 描述文件
-package.json 用于表达非代码的相关信息
-注意:json文件里面不能写注释
npm
- NPM(node package manager)
- NPM用来帮助node完成第三方模块(包)的发布、安装和依赖
命令
- npm -v 查看版本
- npm version 查看所有模块版本,还可以看v8引擎版本、node版本
- npm search 包名 查找包
- npm init 创建json文件,初始化当前项目的npm 注意:包名不能包含大写
- npm install 包名 安装包
- npm install 包名 --save 安装包并添加到依赖中(经测试:如今好像跟npm init 包名 没什么区别)
- npm install 下载当前项目所依赖的包(json文件里面的dependencies部分)注意:运行从网上下载的nodejs项目时,一般先执行这个命令
- npm install -g 全局安装
- npm remove 包名 删除包
淘宝npm镜像
npm搜索包的流程
node在使用模块名字来引入模块时,它会首先在当前目录的node_modules中寻找是否含有该模块
如果有则直接使用,如果没有则去上一级目录的node_modules中寻找
如果有则直接使用,如果没有则再去上一级目录寻找,直到找到为止
直到找到磁盘的根目录,如果依然没有,则报错
buffer
buffer
- buffer 缓冲区
- 结构类似数组,操作方法也跟数组类似
- js数组中不能存储二进制文件,而buffer就是专门用来存储二进制文件的
- 使用buffer不需要引入模块,直接使用即可
- 在buffer中保存的数据都是二进制数据,但是在显示时都是以16进制显示的,因为二进制太长了
- buffer中每一个元素的范围是从00 - ff (00000000 - 11111111)(0 - 255)
- buffer是直接对内存的操作?
事例
- 根据字符串创建
var str = "hello n呀";
var buf = Buffer.from(str);
console.log(str); // hello n呀
console.log(buf); // <Buffer 68 65 6c 6c 6f 20 6e e5 91 80>
console.log(str.length); // 字符串的长度 8
console.log(buf.length); // 占用内存的大小 10字节 (一个英文字母一个字节,一个汉字三字节)
- 创建指定大小的buffer
var buf = Buffer.alloc(10); // 创建10字节大小的buf
buf[0] = 88;
buf[1] = 255;
buf[2] = 0xaa; // 0x表示16进制
buf[10] = 16; // 不起作用,buffer一旦确定大小,不会改变
buf[3] = 556; // 超过255时,只取对应二进制数的后八位
console.log(buf[1]); // 255
console.log(buf[1].toString(16)); // ff
console.log(buf[1].toString(2)); // 11111111
console.log(buf.toString()); // 直接将buf装换成字符串
for(var i = 0; i < buf.length; i++){
console.log(buf[i]);
}
var buf = Buffer.allocUnsafe(10); // 创建一个指定大小的buf,但是不会把内存都变为00,而是保留内存原有的值
console.log(buf);
文件系统
fs(文件系统)
- 简单来说就是通过node来操作系统文件
- node通过fs模块来和文件系统进行交互
引入
- 引入fs模块
var fs = require("fs");
文件的写入
同步写入
- 打开文件
fs.openSync(path,flags[,mode])
path--要打开文件的路径
flags--打开方式 r只读的 w可写的
mode--设置文件的操作权限,一般不传
该方法会返回一个文件的描述符作为结果,我们可以通过该描述符来对文件进行个中操作 - 向文件写入内容
fs.writeSync(fd,string[,position[,encoding]]);
fd--文件描述符
string--要写入的内容
position--写入的起始位置
encoding--写入的编码 - 保存并关闭文件
fs.closeSync(fd);
异步写入(优点:不会阻碍程序的执行 缺点:可读性变差)
异步调用的方法,结果都是通过回调函数的参数返回的
- 打开文件
fs.open(path,flagst,mode,callback)
回调函数的两个参数:
err--错误对象,如果没有错误则为null
fd--文件的描述符
实例fs = require("fs"); fs.open("hello.txt","w",function(err,fd){ if(!err){ console.log(fd); }else{ console.log(err); } }); - 写入
fs.write(fd,string[,position[,encoding]],function(err,written,string){}) - 关闭
fs.close(fd,callback)
简单的写入
- fs.writeFile(file,data[,option],callback)
- fs.writeFileSync(file,data[,option])
- file:文件路径 data:要写入的数据 flag: r只读 w可写 a追加
- 不需要对文件进行打开或者关闭操作,所以是简单文件写入
- 其实该方法就是对fs.open等方法的一个封装
- 实例
对文件的追加
var fs = require("fs");
fs.writeFile("hello.txt","什么",{flag:"a"},function(err){});
往桌面写入文件
var fs = require("fs");
fs.writeFile("C:\\Users\\Administrator\\Desktop\\hello.txt","什么",{flag:"a"},function(err){});
//或者fs.writeFile("C:/Users/Administrator/Desktop/hello.txt","什么",{flag:"a"},function(err){});
//因为\代表转义,所以要用\\或者/
流式文件写入
why
- 同步、异步、简单文件写入都不适合大文件的写入,性能较差,容易导致内存溢出
- 流式文件写入就可以解决这个问题
流式
var fs = require("fs");
var ws = fs.createWriteStream("hello1.txt");
//监听流的打开或者关闭
ws.once("open",function(){
console.log("流打开了");
});
ws.once("close",function(){
console.log("流关闭了");
});
ws.write("你好啊\n");
ws.write("I am fine\n");
ws.write("I dont't no");
//关闭流
ws.end(); // 或者ws.close();
简单的文件读取
文件读取
1.同步文件读取
2.异步文件读取
3.简单文件读取
4.流式文件读取
简单的文件读取
- fs.readFile(path[,options],callback)
var fs = require("fs");
fs.readFile("hello.txt",function (err,data) {
console.log(data.toString());
});
//data是一个buffer对象(因为读取的文件还有可能是图片等二进制文件,所以用一个buffer返回数据)
var fs = require("fs");
fs.readFile("img.jpg",function (err,data) {
if(!err){
fs.writeFile("newImg.jpg", data, function () {
});
}else{
console.log(err);
}
});
流式的文件读取
作用
- 流式文件读取也适用一些大文件,可以分多次将文件读取到内存中
var fs = require("fs");
var rs = fs.createReadStream("img.jpg");
//监听流的开启和关闭
rs.once("open",function(){
console.log("流开启了");
});
rs.once("close",function(){
console.log("流关闭了");
});
//读取流,要读取流中的数据就必须绑定一个data事件
//当文件太大时,这个读取会分多段读取,但是流的开启跟关闭还是只有一次
rs.on("data",function(data){
console.log(data.length);
});
流式读取与流式写入的结合
var fs = require("fs");
var rs = fs.createReadStream("img.jpg");
var ws = fs.createWriteStream("new.jpg");
//监听流的开启和关闭
rs.once("open",function(){
console.log("读取流开启了");
});
rs.once("close",function(){
console.log("读取流关闭了");
//读取流关闭是就关闭写入流
ws.end();
});
ws.once("open",function(){
console.log("写入流开启了");
});
ws.once("close",function(){
console.log("写入流关闭了");
});
//读取流,要读取流中的数据就必须绑定一个data事件
//当文件太大时,这个读取会分多段读取,但是流的开启跟关闭还是只有一次
rs.on("data",function(data){
ws.write(data);
});
rs.pipe()
- 可以将可读流中的内容直接输出到可写流中,就不用像上边那么麻烦了
目录操作
-
验证路径是否存在
fs.exists(path,callback)
fs.existsSync(path) -
获取文件信息
fs.stat(path,callback)
fs.statSync(path) -
删除文件
fs.unlink(path,callback)
fs.unlinkSync(path) -
列出文件
fs.readdir(path[,options],callback)
fs.readdirSync(path[,options]) -
截断文件
fs.truncate(path, len, callback)
fs.truncateSync(path, len) -
建立目录
fs.mkdir(path[, mode], callback)
fs.mkdirSync(path[, mode]) -
删除目录
fs.rmdir(path, callback)
fs.rmdirSync(path) -
重命名文件和目录
fs.rename(oldPath, newPath, callback)
fs.renameSync(oldPath, newPath) -
监视文件更改写入
fs.watchFile(filename[, options], listener) -
判断是文件还是文件夹
fs.stat('./',(err,stats) => {
if(stats.ifFile()){
console.log('是文件');
}else{
console.log('是文件夹');
}
})
链式流
var fs = require("fs");
var zlib = require("zlib");
var data = '';
var readerStream = fs.createReadStream('input.txt');
var zib = zlib.createGzip();
var writeStream = fs.createWriteStream('input.txt.gz');
readerStream.pipe(zib);
zib.pipe(writeStream);
//readerStream.pipe(zib) 会有一个返回值,指向zib,所以可以有如下的写法
//上面的写法可以简写成如下方式
// fs.createReadStream('input.txt')
// .pipe(zlib.createGzip())
// .pipe(fs.createWriteStream('input.txt.gz'));
EventEmittemd
1.直接看例子
// 引入events模块
var events = require('events');
// 创建EventEmitter对象
var event = new events.EventEmitter();
var event2 = new events.EventEmitter();
// 为EventEmitter对象本身的事件注册监听器
// newListener事件会在EventEmitter对象添加新的监听器时触发(它跟我们自己定义的事件不同,不是通过emit触发的)
event.on('newListener',function (event,listener) {
console.log(event);
});
// 为自定义的事件注册监听器
event.on('触发',fn1);
event.on('触发',fn2);
event.on('非触发',fn2);
event.emit('触发');
function fn1() {
console.log('我是函数1');
}
function fn2() {
console.log('我是函数2');
}
简单的路由
将请求的路径(pathname)传递给路由
var fs = require("fs");
var http = require("http");
var path = require("path");
var url = require("url");
// 搭建简单的静态服务器
// 定义一个函数,使得能够根据url的路径来返回相应的页面
function reqFile(req, res) {
var pathObj = url.parse(req.url); // url.parse()将一个url字符串转换为对象兵返回
if (pathObj.pathname === "/") {
pathObj.pathname += "index.html";
}
var filePath = path.join(__dirname, "html", pathObj.pathname);
fs.readFile(filePath, 'binary', function(err, fileContent) {
if (err) {
res.writeHead(404, 'not found');
res.end('<h1>404 not found<h2>');
} else {
res.writeHead(202, 'OK');
res.write(fileContent, 'binary');
res.end();
}
});
}
var server = http.createServer(function(req, res) {
reqFile(req, res);
});
server.listen(8080);
console.log('visit 8080');

浙公网安备 33010602011771号