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镜像

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');
posted @ 2020-04-15 20:19  Mrzhozho  阅读(75)  评论(0)    收藏  举报