●●●●●命令提示符
cmd窗口/小黑屏/shell/终端
cmd或者附件中
常用指令:
去哪个磁盘就用C:或D:或E:直接回车就进入指定磁盘\
dir 列出当前目录下所有文件\
cd 进入到指定目录\
语法: cd 目录名\
例如: cd Desktop(可以使用Tab快捷键补全)\
md 创建文件夹\
语法: md 目录名\
例如: md node\
注意: 如果想在桌面创建必须先找到Desktop\
例如:...Desktop>md 游戏\
rd 删除一个文件夹\
语法; rd 目录名\
例如: rd 游戏(注意前面必须保持一致也是Desktop)\
上下键可以查询历史记录\
目录:
. 表示当前目录
用法例如: cd.
.. 表示上一级目录
用法例如: cd..
●●●●●环境变量(window系统中的变量)
①可以在path中改,也可以自己创建一个新的变量(变量名和变量值),注意变量名中的各个路径之间用 英文分号 隔开
②注意:刚改完之后不会生效,必须要重启命令提示符
知识点:当我们在命令行窗口打开一个文件或调用一个程序时,系统现在当前目录下寻找文件程序,如果没找到则会依次到环境变量path中找,直到找到为止,如果最后找不到则报错(和再作用域链中找变量一样),所以我们可以将经常访问的程序和文件路径添加到path中,这样可以在任意位置打开这些文件和程序了
●●●●●进程和线程
进程
①进程负责为执行的程序提供必备的环境,简单理解就是我们写的代码都是存在进程里的
②进程相当于工厂里的车间\
线程
①线程是计算机中最小的计算单位,线程负责执行进程的程序
②线程相当于车间中的工人
理解:任务管理器中cpu为0的就是没有工人干活的
单线程
js是单线程
node.js 属于单线程
多线程
●●●●● 知识点: node奇数版本为开发版本,bug比较多,偶数版本为稳点个版本,所以一般用偶数版本
●●●●●
命令行窗口写代码
...换行的时候三个点表示还没输完
●●●●●模块化
1、在node中,通过require()来引入外部模块
①require()可以传递一个模块的路径来作为参数(这里的路径如果是相对路径,必须使用.或..开头,即使是./也不能省略)
例如: require("./02.node.js");
②使用require()引入模块以后,该函数会返回一个对象,这个对象代表的是引入的模块
2、在node中,一个js文件就是一个模块 ①在node中,每一个js文件中的js代码都是独立运行在一个函数中,而不是在全局作用域中,相当于一个闭包,所以一个模块中的变量和函数无法在其他模块中访问 我们可以通过exports来暴露变量只需要将需要暴露给外部的变量和方法设置为exports的属性即可
3、使用require()引入外部模块时,使用的就是模块标识,我们可以通过模块标识来找到指定的模块
模块分成两大类
1、核心模块
①核心模块就是由node引擎提供的模块
②模块标识就是模块名字,直接可以引入
例如: var fs = require("fs");
2、文件模块
①用户自己创建的模块
②文件模块的标识就是文件的路劲(绝对路径、相对路径)
●●●●●检查一个变量在什么作用域中
1、在node中有一个全局对象global,它的作用和网页中window类似
①全局中创建的变量都会作为global的属性保存
②全局中创建的函数都会作为global的方法保存
例如: var a = 10;
console.log(global.a); // undefined
a = 10;
console.log(global.a); // 10
总结:使用var声明变量是在函数作用域中,不使用var声明的是全局变量
2、arguments(只有函数中有arguments这个属性,全局是没有的,所以可以通过这个arguments属性来证明这是一个函数)
而arguments.callee这个属性保存的是当前执行的函数对象\
例如:
console.log(arguments); // 返回的是下面函数的五个参数
console.log(arguments.callee); // [Function]
console.log(arguments.callee + ""); // 加个空串做拼串变成字符串,会显示出函数体
理解:是因为在node执行模块中的代码时,它会用下面这个函数把内容包起来
function(exports,require,module,_filename,_dirname){
内容....
}
五个参数含义:
exports
该对象用来将变量或函数暴露在外部
require
函数,用来引入外部模块
module
①module代表当前模块本身
②exports是module的属性
console.log(module.exports == exports); // true
③既可以使用exports导出,也可以使用module.exports导出
_filename
当前模块的完整路径
_dirname
当前模块所在文件夹的完整路径
★★★★★
知识点:
基本数据类型的值之间是相互独立的(保存在栈内存中)
举例说明: var a = 10
var b = a 此时的a和b都是10
a++
console.log(a) // 11
console.log(b) // 10
引用数据类型(是在堆内存中保存的)
举例说明: var obj = new Object()
obj.name = '孙悟空'
var obj2 = obj 此时obj.name和obj2.name都是孙悟空
obj2.name = '猪八戒' 此时obj.name和obj2.name都是猪八戒
obj2=null 此时obj.name还是猪八戒
画图说明:
栈内存 堆内存
变量 值
①var obj = new Object() obj obj堆内存地址0x00 内存地址为0x00的空间
②obj.name = '孙悟空' 此时obj对象里面有了name='孙悟空'
③var obj2 = obj obj2 obj堆内存地址0x00
④obj2.name = '猪八戒' 此时内存地址为0x00的空间里面name数据换成了name='猪八戒'
⑤obj2=null ——值为null就相当于栈内存obj2和堆内存连接的线断了——,但是对obj没有影响,栈内存obj和堆内存的线还在
解析:var obj = {} 其中obj是变量在栈内存中,{}是对象,在堆内存中,步骤④obj2.name是在改对象,所以对obj有影响,步骤⑤obj2 = null是在改变量,所以对obj没影响
注意:以后碰到这种问题①先注意var obj = {}其中obj是变量在栈内存中,{}是对象,在堆内存中②然后脑海形成这幅图并连接线
所以: module.exports既可以通过.的形式暴露,也可以通过直接赋值 module.exports.xxx = xxx; module.exports = {}; exports只能通过.的形式来暴露 exports.xxx = xxx;
●●●●●包
包实际上就是一个压缩文件,解压后还原为目录,符合规范的包应该包涵以下目录(一般在根目录下)
package.json 描述文件(当自己写了一个想让所有人都用的包,这个是用来干嘛的,可以写在package.json文件中)
bin 可执行二进制文件(就是可以直接在计算机执行的文件)
lib js代码
doc 文档
test 单元测试
注意:
①package.json 是必须有的,其它几种都是可有可无
②JSON文件中不能写注释\
NPM(包管理工具)就相当于软件商店,可以在里面下载各种包
①对于node而言,npm帮助其完成第三方模块 安装、发布、依赖 等(就是当你下载一个东西时,这个东西版本对不对,需要依赖什么,npm都会帮你下载好)
②CommonJS的包规范由包结构和包描述文件两部分组成
包结构
用于组织包中的各种文件
包描述文件
描述包的相关信息 ,以供外部读取分析
③通过npm下载下来的所有包都在node_modules文件夹中,可以直接引入使用
例如下载了一个math(npm install math),就可以直接在该js文件夹中 var app = require('math') 使用
●●●●●NPM(Node Package Manager)
CommonJS包规范是理论,NPM是其中一种实践
对于Node而言,NPM帮助其完成了第三方模块的发布、安装和依赖等。借助NPM、Node与第三方模块之间形成一个很好地生态系统\
npm的命令:
●●npm -v
查看npm的版本
●●npm version
npm版本和所有模块都打印出来
●●npm search xxx
搜索包
●●npm install xxx (注意:如果没有安装到指定包,是因为该文件没有package.json文件夹,npm不确定它是一个包,此时可以先用npm init 初始化该文件夹,使其变成包)
简写:npm i xxx
安装包
●●npm install
下载当前项目所依赖的包(也就是package.json中的dependencies里面配置的依赖)
●●npm install xxx --global
简写:npm i xxx -g
全局安装包(全局安装的包一般都是一些工具例如:编译css文件的,编译js文件的等等)
●●npm install xxx --save-dev
简写:npm i xxx -D
对模块进行局部安装,模块写入到devDependencies(开发环境)对象
●●npm install xxx --save
简写:npm i xx -S
同上也是对模块进行局部安装,不同的是模块写入到 dependencies(生产环境)对象
●●npm remove xxx
简写:npm r xxx
删除包
●●npm remove xxx --save
从依赖里面删除包
●●npm init
初始化生成package.json文件
●●npm view xxxx versions
查看模块全部版本
●●npm cache clean
别名: npm cache clear
强制清除缓存: npm cache clear --force
包创建步骤:
①先用npm init 初始化一下,此时会显示最下方会显示name...等等,(注意:严格来讲npm中的name不能出现大写字母,所以例如helloOk可以用hello_ok来代替)
② description 填写一个描述
entry point 入口 点,表示哪个文件是程序的入口
③此时就可以直接在该包创建一个js文件夹使用了
知识点:
①使用npm install xxx --save安装的包在依赖里面,一般上传时类似node_modules这种包是不会上传的
原因一:上传下载的速度很慢
原因二:不能保证文件是最新的版本
②假如一个文件package.json中依赖(dependencies)有很多包,是不需要一个一个下载的,只要有package.json文件并且dependencies中有依赖的包,用户直接在该文件夹下命令行窗口npm install就可以了
所以我们以后在网上下载下来的那些包不要直接使用,先npm install一下
●●●●●cnpm
npm是国外的cnpm是npm的镜像,cnpm和npm用法一样,指令也一样
例如:安装express框架cnpm i express --save
●●●●●node搜索包的流程
node在使用模块名字来引入模块时,流程是:先从当前目录的node_modules寻找,如果有直接使用,如果没有再去上一级目录的node_modules一直到找到磁盘如果还没有则报错(桌面不属于上级目录,如果模块在桌面,也会引入失败报错)
●●●●●Buffer(缓冲区/缓冲器,用来保存传输数据)
①由于js数组中不能存储二进制文件,所以不是很吃香,而buffer就是专门用来存储这些二进制数据的
②Buffer结构和数组结构很像,操作方法也和数组类似
③使用buffer不需要引入模块,直接使用即可Buffer.from()
④buffer中存储的都是二进制数据,但在显示时是以十六进制显示的,其实也就是unicode编码前边没有00(因为十六进制方便观看,计算机保存是二进制,显示的时候都会转换为十六进制显示)
⑤buffer中每个元素的范围是00-ff
ff转换成二进制就是11111111,其实也就是00000000-11111111范围,表示8bit,8bit=1byte/字节,所以Buffer中一个元素占用内存的一个字节
例如: var str = 'hello atguigu'
var buf = Buffer.from(str)
console.log(buf.length) // 13 注意:这里是占用内存大小
console.log(str.length) // 13 这里是字符串长度
以上是英文如果换成中文
var str = 'hello 尚硅谷'
var buf = Buffer.from(str)
console.log(buf.length) // 15 占用内存大小(因为一个汉字占用三个字节)
console.log(str.length) // 9 字符串长度
0-255(ff就是十进制的255)
⑥创建一个指定内存大小的buffer方法:
方法一:
var buf = Buffer.alloc(10); 创建一个长度10并且连续的缓冲区
buf[0] = 88; 索引0为58(因为传递了十进制数字,返回的是十六进制数字)
buf[1] = 255; 索引1为ff
buf[2] = 0xaa; 索引2为aa
buf[10] = 15; 没有索引10,也不显示索引10但也不报错(因为Buffer大小一旦确定就不能修改,Buffer实际上是对底层内存的直接操作,所以这里索引10写了也没用)
buf[3] = 256; 索引3为00(因为超过了255,也就是超过了buffer规定的每个元素范围00-ff)
buf[4] = 556; 索引4为2c(2c转换成二进制是101100,而556转换成二进制是1000101100,因为每个元素范围是00000000-11111111只能保存8位,此时是保存了后八位,前面两个0舍去就是101100,所以显示2c)
console.log(buf);
console.log(buf[2]); // 170 (只要是在控制台或页面输出,就一定显示十进制,而计算器中170转换成十六进制就是AA)
console.log(buf[2].toString(16)); // aa (如果非要看十六进制怎么办,只要是数字就没法转换成十六进制,可以用toString()方法将其转换成字符串,括号内16就是转换成十六进制,2就是二进制)
for(var i = 0, i < buf.length, i++){console.log(buf[i])}
如果将其遍历出来,也是以十进制显示的
方法二:
var buf = Buffer.allocUnsafe(10);
1、这种方法中可能含有敏感数据(因为这个内存不是你一个人在使用,Buffer.alloc(10)是创建出10个位的空间并把空间内元数据删除,而Buffer.allocUnsafe(10)不删除直接创建10个位空间,会有旧数据显示出来)
2、既然Buffer.allocUnsafe(10)会泄露隐私,为什么还会有这种方法,是因为Buffer.allocUnsafe()方法好,不会删除元数据,而Buffer.alloc()方法会删除元数据,但是我们一般还是用Buffer.alloc()因为它不会泄露隐私
总结:
buffer作用/为什么叫缓冲区:用户发送请求的数据转换成二进制存储在buffer中(传输数据的一个容器)
如果用户发送了一段数据 var buf = Buffer.from('我是一段数据')
console.log(buf) //显示的是二进制数据
console.log(buf.toString()) // '我是一段数据' (可以使用toString()方法将其转换成字符串)
Buffer.from() 将一个字符串转换成buffer
Buffer.alloc() 创建一个指定大小buffer
var buf = Buffer.allocUnsafe();
...还有很多Buffer方法可以参考官网
●●●●●fs(File System)文件系统
含义: ①文件系统就是通过node来操作系统中的文件
使用: ②使用文件系统,需要先引入fs模块,fs是核心模块,直接引入不需要下载
例如: var fs = require("fs");
fs模块中所有操作都有两个形式选择:同步和异步
一:同步手动操作的步骤:
1、打开文件
语法:fs.openSync(path,flags[,mode]);
path 要打开文件的路径
flags 打开文件要做的操作类型
r 只读的
w 可写的
等等....
mode 设置文件的操作权限(你看它套了一个中括号,因为这是一个可选的,一般不传)
返回值:该方法会返回一个文件的描述符作为结果,我们可以通过该描述符来对文件进行各项操作
例如: var fd = fs.openSycn("hello.txt","w");这是一个相对路径(表示打开我当前文件目录下的hello.txt文件)
console.log(fd) // 3 (此时该文件已经打开了,编号为3,可以通过3这个描述符来操作该文件)
2、向文件中写入内容(注意向文件中写内容必须先执行第一步打开文件)
语法:fs.writeSycn(fd,string[,position[,encoding]]);
fd 文件描述符
string 写入的内容
position 写入的起始位置(可选的)
encoding 写入的编码,默认是utf-8(可选的)
例如:fs.writeSycn(fd, "今天天气不错~~~");
此时打开hello.txt文件就可以看到写的内容了——>今天天气不错~~~
fs.writeSycn(fd, "今天天气不错~~~" 2);
此时打开hello.txt文件就可以看到写的内容了——>□□今天天气不错~~~
2表示从索引为2的位置开始写,为什么显示□□是因为这里面没写,是一堆0,所以显示的效果就是□□
3、保存并关闭文件
语法:fs.closeSycn(fd);‘
总结:
var fs = require("fs");
var fd = fs.openSycn("hello.txt","w");
fs.writeSycn(fd, "今天天气不错~~~");
fs.closeSycn(fd);
为什么要使用这种方式呢?
①如果需要写很多文件呢,,这种方式适合大批量写
为什么必须要第三步关闭呢?
①在这里因为此时我们程序停止了,所以他就自动保存了,如果是一个例如百度的服务器呢,它是不能停止的,所以可以用这种方式来保存
②而且这是一个fs.js文件,它会一直占用内存,如果打开过多文件,计算机可能就死了,所以操作完以后必须关闭
二:异步手动操作步骤(其实参数基本一致,就是多了一个callback回调函数)
1、打开文件
语法:fs.open(path,flags[,mode],callback);
callback 异步调用的方法都是通过回调函数的参数来返回的
fs.open('hello.txt', 'w', function(){
conslole.log(arguments); // {'0': null, '1': 3}
}
回调函数中的两个参数:
第一个参数:错误对象,如果没有错误则为null
第二个参数:文件的描述符
fs.open('hello.txt', 'w', function(err, fd){
if(!err){
console.log(fd); // 3
2、向文件中写入内容 fs.write(fd,"写入内容",function(err){
if(!err){
console.log('写入成功'); // "写入成功"(写不写都行)
}
3、保存并关闭文件 fs.close(fd,function(err){
if(!err){
console.log('关闭成功'); // "关闭成功"(写不写都行)
}
}
}
}else{
console.log(err); // (此时如果把wgaichnegr并且把文件删除就会报该文件不存在的错误信息)
}
}
总结:
①异步是先执行后面代码,然后再执行回调函数内代码
②异步没有返回值,它是通过回调函数返回值的,只有同步有返回值
③fs.write(fd,"写入内容",function(err,written,string){} 写入的回调函数内有三个参数,只是讲课没用到,详情参考官网
★★简单文件
语法: fs.writeFile(file,data[,options],callback);
fs.writeFileSycn(file,data[,options]);
file 要操作的文件的路径
data 写入内容
options 选项,可以对写入进行一些设置(可选的,一般看到options配置的就是一个对象,例如{flag: 'w'})
callback 写入完成后要执行的回调函数
例如:
var fs = require("fs");
fs.writeFile("hello.txt", "这是简单文件写入的内容", {flag: 'w'}, function(err){
if(!err){
console.log("写入成功"); // "写入成功"
}else{
console.log(err);
}
});
注意:
①会带哦函数内只有一个参数
②原理和同步异步写入一样,简单文件只是使用writeFile进行了封装(可以点击writeFile打开查看封装原理)
③如果hello.txt文件中本来有内容,那么通过w写入的性质就是(截断/全部覆盖)如果想追加不是截断可以使用{flag: 'a'},w是文件不存在就创建文件,r+是文件不存在就报错,其他方法可以参考文档
④如果路径是绝对路径,例如C:\OK\OK\OK\hello.txt,那么一个\表示转义字符,所以应该写成\\或者/
应该写成C:\\OK\\OK\\OK\\hello.txt 或者 C:/OK/OK/OK/hello.txt
★★流式文件
fs.createWriteStream(path[,options]);
可以用来创建一个可写流
path 路径
options 配置的参数
①以上几种方式有一个隐患:如果是一个大文件,1、占用内存太大,2、速度过慢,所以同步异步简单写入都不适合写大文件,性能差,容易导致内存溢出
②流式文件写入是可持续写入的(类似两个水缸中间插入了一个水管,只要水管在,就能一直写入,这样写性能好,不会导致内存溢出)
例如:
var fs = require("fs");
//创建一个可写流
var ws = fs.createWriteStream("hello.txt");
//可以通过监听流的open和close来监听流的打开和关闭
/*
ws.on(事件字符串,回调函数)
可以为对象绑定一个事件,
ws.once(事件字符串,回调函数)
可以为对象绑定一个一次性事件,该事件将会在触发一次后自动失效
*/
ws.once("open",function(){ // 因为open是一个一次性的事件,打开之后函数就没用了,所以用once,这样性能会好一些
console.log("流打开了"); // "流打开了"
});
ws.once("close",function(){
console.log("流关闭了"); // "流关闭了"
});
ws.write("输入了");
ws.write("输入了");
ws.write("输入了");
ws.write("输入了");
....(只要这个流存在,就可以一直写)
//关闭流
//ws.close(); 此时hello.txt文件中只有一个‘输出了’如果不关的话会全部写入四个‘输出了’(相当于拔了水管的一头)
ws.end(); 会全部写入再关闭(相当于拔了水管的另一头)
★★文件读取
1、同步文件读取
2、异步文件读取
3、简单文件读取
4、流式文件读取
3、简单文件读取
fs.readFile(path[,options],callback);
fs.readFileSycn(path[,options]);
path 路径
options 读取的选项(可选,参考文档)
callback 回调函数,通过回调函数将读取到的内容返回(err,data)
参数:
err 错误对象
data 读取到的数据,会返回到buffer(如果读取的是一个图片,那么转换成字符串看不懂,所以data读取的是一个buffer)
例如:
var fs = require("fs");
fs.readFile("hello.txt",function(err,data){
if(!err){
console.log(data.toString());
//将data写入到文件中
fs.writeFile("hello.jpg",data,function(err){
if(!err){
console.log("文件写入成功");
}
});
}
});
图片写入例如:
var fs = require("fs");
fs.readFile("an.jpg",function(err,data){
if(!err){
//将data写入到文件中
fs.writeFile("C:/OK/OK/hello.jpg",data,function(err){ // 注意是hello.jpg
//检查是否有效
if(!err){
console.log("文件写入成功");
}
});
}
});
4、流式文件读取(流式文件也适用读取比较大的文件,可以分多次将文件读取到内存中)
例如:
var fs = require("fs");
//创建一个可读流
var rs = fs.createReadStream("Desktop/hello.mp3");
//创建一个可写流
var ws = fs .createWriteStream("b.mp3");
//同样也可以监听文件rs.once() 这里就不写了
// 方法一:
rs.on('data', function(data){ // 这里必须用on,因为once读一次就不会再读取了,需要持续读取
//如果要读取可读流中的数据,必须为可读流绑定一个data事件,data事件绑定完毕,它会自动开始读取数据
//读取
console.log(data)
//将读取到的数据写入另一个文件中
ws.write(data)
//注意可写流写完之后关闭在哪里,可以在上面的监听文件时rs.once('close',function(){ws.end()})中关闭
})
// 方法二:
//pipe()可以将可读流中的内容直接输出到可写流中,写完自动关闭(pipe就是管道的意思,相当于在rs和ws之间连接一个管道)
rs.pipe(ws);
●●●●●fs模块其他方法
★★检查一个文件是否存在
fs.existsSycn(path);
★★获取文件状态
fs.stat(path,callback);
fs.statSycn(path);
它会返回一个对象,该对象保存了当前对象状态的相关信息
例如:
var fs = require('fs')
fs.stat("a.mp3",function(err,stat){
console.log(arguments); //检查该对象存在不存在
console.log(stat); // 当前对象的相关信息
//会显示出以下
//size 文件大小
//isFile() 是否是文件
//isDirectory() 是否是文件夹(目录)
//....等等该对象信息
console.log(stat.size);
});
★★删除文件
fs.unlink(path,callback);
fs.unlinkSycn(path);
★★读取一个目录的目录结构
fs.readdir(path[,options],callback);
fs.readdirSycn(path[,options]);
. 表示当前目录
例如: fs.readdir(".",function(err,files){ // files是一个字符串数组,每一个元素就是一个文件或文件夹的名字
if(!err){
console.log(files);
}
});
★★截断文件,将文件修改为指定大小
fs.truncate(path,len,callback);
fs.truncateSycn(path,len);
例如: fs.truncate('hello.txt', 3)
★★创建一个目录
fs.mkdir(path[,mode],callback);
fs.mkdirSycn(path[,mode]);
★★删除一个目录
fs.rmdir(path,callback);
fs.rmdirSycn(path);
★★对文件进行重命名,可以改文件名或者路径(相当于剪切功能)
fs.rename(oldpath,newpath,callback);
fs.renameSycn(oldpath,newpath);
oldpath 旧路径//文件名
newpath 新路径//文件名
callback 回调函数
★★监视文件修改
fs.watchFile(filename[,options],listener);
filename 监视的文件名字
options 配置选项
listener 回调函数,当文件发生变化时,回调函数会执行
回调函数中有两个参数
curr 当前文件的状态
prev 修改之前文件的状态
这两个对象都是stats对象
例如:
var fs = require('fs')
fs.watchFile('hello.txt', {interval:1000}, function(curr, prev){
//interval指定修改的时间(官方文档说的默认是5007ms一次)
console.log('修改前文件大小'+prev.size)
console.log('修改前文件大小'+curr.size)
})
为什么会这么迟钝?
因为他检查是有一个时间间隔的,可以使用interval修改检查间隔时间