- 模块化
- ES5中没有原生支持模块化,我们只能通过script标签引入js文件来实现模块化
- 在node中为了对模块管理,引入了CommonJS规范
- 模块的引用
- 使用 require()函数来引入一个外部的模块,require()可以传递一个文件的路径作为参数,
node将会自动根据该路径来引入外部模块,这里的路径,若是相对路径则必须要以.或者..开头
- 例子:
var 变量 = require("模块的标识");
- 模块的定义
- 在node中一个js文件就是一个模块,定义一个模块就是创建一个js文件
- 默认情况下在js文件中编写的内容,都是运行在一个独立的函数中,不是全局作用域
因此一个模块中的变量和函数外部的模块无法访问
- 导出变量和函数
- 使用 exports
- 例子:
exports.属性 = 属性值;
exports.方法 = 函数;
- 使用module.exports
- 例子:
module.exports.属性 = 属性值;
module.exports.方法 = 函数;
module.exports = {};
- 模块的标识
- 模块的标识就是模块的名字或路径
我们node通过模块的标识来寻找模块的
对于核心模块(npm中下载的模块),直接使用模块的名字对其进行引入
var fs = require("fs");
var express = require("express");
对于自定义的文件模块,需要通过文件的路径来对模块进行引入
路径可以是绝对路径,如果是相对路径必须以./或 ../开头
var router = require("./router");
模块A:moduleA.js
console.log("module A")
模块B:moduleB.js
在模块A中引入模块B
// 使用 require()函数来引入一个外部的模块,require()可以传递一个文件的路径作为参数,
// node将会自动根据该路径来引入外部模块,这里的路径,若是相对路径则必须要以.或者..开头
require("./moduleA.js")
在node中一个js文件就是一个模块,定义一个模块就是创建一个js文件
模块A:moduleA.js
// 默认情况下在js文件中编写的内容,都是运行在一个独立的函数中,不是全局作用域
// 因此一个模块中的变量和函数外部的模块无法访问
console.log("module A")
var x = 1
var y = 2
// Node中模块的代码相当于如下:
(function(){
console.log("module A")
var x = 1
var y = 2
})()
模块B:moduleB.js
// 引入moduleA.js模块
var md = require("./moduleA.js")
console.log(md.x) // 输出undefined
模块A:moduleA.js
// 我们可以通过exports来向外部暴露变量和方法,只需要将需要暴露给外部的变量或方法设置为exports的属性即可
console.log("module A")
exports.x = "module A 的x"
exports.y = "module A 的y"
exports.fn = function(){}
// Node中模块的代码相当于如下:
(function(){
console.log("module A")
exports.x = "module A 的x"
exports.y = "module A 的y"
})()
模块B:moduleB.js
// 引入moduleA.js模块
var md = require("./moduleA.js")
console.log(md)
/*
输出:
module A
{ x: 'module A 的x', y: 'module A 的y', fn: [Function (anonymous)] }
*/
模块的标识就是模块的名字或路径,使用require()引入模块时,使用得就是模块标识,我们可以通过模块标识来找到指定得模块
模块可分为两类
定义一个模块math
exports.add = function(a,b){
return a+b
}
exports.mul = function(a,b){
return a*b
}
var math = require("./math")
console.log(math.add(1,2))
console.log(math.mul(2,3))
默认情况下在js文件中编写的内容,都是运行在一个独立的函数中,不是全局作用域
因此一个模块中的变量和函数外部的模块无法访问
/**
* 在node中有一个全局对象global,他得作用和网页中得window类似,
* 在全局中创建得变量都会作为global得属性保存
* 在全局中创建得函数都会作为global得方法保存
*/
var a = 10
console.log(global.a) // undefined
// 在模块中如果不用var声明得变量,那么变量就是全局变量
a = 10
console.log(global.a) // 10
arguments是伪数组,是封装在函数中获取参数的,全局中没有arguments
a = 10
// console.log(global.a)
console.log(arguments.length) // 输出5
arguments.callee:保存的是当前执行的函数对象
a = 10
console.log(arguments.callee) // [Function (anonymous)]
a = 10
console.log(arguments.callee+"")
// 输出内容如下
function (exports, require, module, __filename, __dirname) {
a = 10
console.log(arguments.callee+"")
}
当node在执行模块中的代码时,会在自己编写代码包裹进函数中,作为函数体,因此模块中的变量都是局部变量
exports,
require,:
module:
__filename:
__dirname:
exports和module.exports
exports
通过exports只能使用点的方式来向外暴露内部变量
exports.XXX = yyy
module.exports
// module.exports.name = "swk"
// module.exports.age = 18
// module.exports.sayNAme = function(){
// console.log("我是孙悟空")
// }
// exports = {} 这里如果直接使用exports就不能暴露
module.exports = {
name:'swk',
age:18,
sayNAme(){
console.log("123")
}
}
var md = require("./helloModule")
md.sayNAme()
CommonJS的包规范允许我们将一组相关的模块组合到一起,形成一组完整的工具
CommonJS的包规范由包结构和包描述文件两部分组成
包结构
包描述文件
包实际上就是一个压缩文件,解压以后还原伪目录。符合规范的目录应该包含如下文件:
包描述文件用于表达非代码相关的信息,它是一个JSON格式的文件-package.json位于包的根目录下,是包的重要组成部分。
package.json中的字段
name ,description,version、 keywords、maintainers、contributors、bugs、
licenses、repositories、dependencies、homepage、os、cpu、engine、builtin、directories、implements、scripts、author、bin、main、devDependencies。
- npm的命令
- npm -v 查看npm的版本
- npm version 查看所有模块的版本
- npm search 包名 搜索包
- npm init 创建package.json
- npm install / i 包名 安装包
- npm remove / r 包名 删除包
- npm remove / r 包名 --save 删除包并删除依赖
- npm install 包名 --save 安装包并添加到依赖中 *****
- npm install 下载当前项目所依赖的包
- npm install 包名 -g 全局安装包(全局安装的包一般都是一些工具)
node在使用模块名字来引入模块时,它会首先在当前目录的node_modules中寻找是否含有该模块
如果有则直接使用,如果没有则去上一级目录的node_modules中寻找
如果有则直接使用,如果没有则再去上一级目录寻找,直到找到为止直到找到磁盘的根目录,如果依然没有,则报错
从结构上看Buffer非常像一个数组,它的元素为16进制的两位数。
实际上一个元素就表示内存中的一个字节。汉字占两个字节。
实际上Buffer中的内存不是通过JavaScript分配的,而是在底层通过C++申请的。
也就是我们可以直接通过Buffer来创建内存中的空间。
/*
Buffer(缓冲区)
-Buffer的结构和数组很像,操作的方法也和数组类似
-数组中不能存储二进制的文件,而buffer就是专门用来存储二进制数据-使用buffer不需要引入模块,直接使用即可
-在buffer中存储的都是二进制数据,但是在显示时都是以16进制的形式显示
- buffer中每个元素得范围是从00 - ff
- Buffer的大小一旦确定,则不能修改,Buffer实际上是对底层内存的直接操作
*/
var str = "hello atguigu"
// 将一个字符串保存到buffer中
var buf = Buffer.from(str)
console.log(buf.length) // 13 占用内存大小
console.log(str.length) // 13 字符串得长度
console.log(buf) //
// 创建一个指定大小的buffer
// buffer构造函数都是不推荐使用的
var buf2 = new Buffer(1024) // 创建一个1024字节的buffer
// 创建一个10字节的buffer
var buff3 = Buffer.alloc(10)
buff3[0] = 88
buff3[3] = 55
buff3[5] = 0xaa
console.log(buff3) //
// Buffer.allocUnsafe(size) 创建一个指定大小的buffer,但是buffer中可能有敏感数据
var buf4 = Buffer.allocUnsafe(10)
console.log(buf4)
/**
Buffer.from(str) 将一个字符串转为buffer
Buffer.alloc(size) 创建一个指定大小的Buffer
Buffer.allocUnsafe(size) 创建一个指定大小的buffer,不清除原来内存中的数据,可能读到敏感数据
buf.toString() 将缓冲区中的数据转换为字符串
*/
var b5 = Buffer.from("我是一段文本数据")
console.log(b5, b5.toString())
在Node中,与文件系统的交互是非常重要的,服务器的本质就将本地的文件发送给远程的客户端
文件系统简单来说就是通过Node来操作系统中的文件
Node通过fs模块来和文件系统进行交互该模块提供了一些标准文件访问API来打开、读取、写入文件,以及与其交互。
要使用fs模块,首先需要对其进行加载 const fs = require(“fs”);
/**
* 文件系统(File system)
-文件系统简单来说就是通过Node来操作系统中的文件
-使用文件系统,需要先引入fs模块,fs是核心模块,直接引入不需要下载
同步文件的写入
-手动操作的步骤
1.打开文件
fs.opensync(path, flags [, mode])
- path要打开文件的路径
- flags 打开文件要做操作的类型
r只读的
w可写的
- 返回值
该方法会返回一个文件的描述符作为结果,我们可以通过该描述符来对文件进行各种操作
2.向文件中写入内容
fs.writeSync(fd, string[, position[, encoding]])
- fd 文件描述符,需要传递要写入文件的描述符
- string 要写入的内容
- position 写入的起始位置
- encoding 写入的编码,默认为utf-8
3.保存并关闭文件
fs.closeSync(fd)
- fd 要关闭文件的描述符
*/
var fs = require("fs")
// 打开文件
var fd = fs.openSync("hello.txt", "w")
// 向文件中写入内容
fs.writeSync(fd, "今天天气真不错")
// 关闭文件
fs.closeSync(fd)
/**
* 异步文件写入
* 1.异步打开文件
* fs.open(path,flags[, mode], callback)
* - 用来打开一个文件
* - 异步调用的方法,结果都是通过回调函数的参数返回的
* - 回调函数的两个参数
* err 错误对象,如果没有错误则为null
* fd 文件描述符
* 2.异步写入
* fs.write(fd, string[, position[, encoding]], callback)
* - 用来异步写入文件
*
* 3.异步关闭
* fs.close(fd, callback)
*/
var fs = require("fs")
// 打开文件
fs.open("hello2.txt", "w", function(err, fd){
// 判断是否出错
if(!err){
// 如果没有出错,则对文件进行写入操作
fs.write(fd, "异步写入的内容",function(err){
if(!err){
console.log("异步写入成功")
}
// 关闭文件
fs.close(fd, function(err){
if(!err){
console.log("文件已关闭")
}
})
})
}else{
console.log(err)
}
})
r 读取文件,文件不存在则出现异常
r+ 读写文件,文件不存在则出现异常
rs 在同步模式下打开文件用于读取
rs+ 在同步模式下打开文件用于读写
w 打开文件用于写操作,如果不存在则创建,如果存在则截断
wx 打开文件用于写操作如果存在则打开失败
w+ 打开文件用于读写,如果不存在则创建,如果存在则载断
wx+ 打开文件用于读写,如果存在则打开失败
a 打开文件用于追加,如果不存在则创建
ax 打开文件用于追加,如果路径存在则失败
a+ 打开文件进行读取和追加,如果不存在则创建该文件
ax+ 打开文件进行读取和追加,如果路径存在则失败
/**
* 简单文件写入
* fs.writeFile(file, data[, options], callback)
* fs.writeFileSync(file, data[, options])
* - file 要操作的文件的路径
* - data 要写入的数据
* - options 选项,可以对写入进行一些设置
* - callback 当写入完成后要执行的函数
*/
// 引入fs模块
var fs = require("fs")
// fs.writeFile("h3.txt", "通过writeFile写入的内容", {flag:'w'},function(err){
// if(!err){
// console.log("写入成功")
// }
// })
fs.writeFileSync("h4.txt", "通过writeFileSync写入", {flag:'a+'})
/**
* 同步,异步,简单文件的写入都不适合大文件的写入,性能较差,容易导致内存溢出
*/
var fs = require("fs")
/**
* 流式文件写入
*
* 创建一个可写流
* fs.createWriteStream(path[, options])
* - 可以用来创建一个可写流
* - path:文件路径
* - options 配置的参数
*/
/**
* 可以通过监听流的open和close事件来监听流的打开和关闭
* on(事件字符串,回调函数)
* - 可以为对象绑定一个事件
*
* once(事件字符串,回调函数)
* - 可以为对象绑定一个一次性事件,该事件将会触发一次以后自动失效
*/
// 创建一个可写流
var ws = fs.createWriteStream("h5.txt")
ws.once("open", ()=>{
console.log("流打开了")
})
ws.once("close", ()=>{
console.log("流关闭了")
})
// 通过ws向文件中输出内容
ws.write("通过可写流写入文件的内容")
ws.write("通过可写流写入文件的内容")
ws.write("通过可写流写入文件的内容")
// 关闭流 不能用ws.close(),这相当于流数据还没写完就断开了
ws.end()
/**
* 1.同步文件读取
* 2.异步文件读取
* 3.简单文件读取
* fs.readFile(path[, options], callback)
* - path 要读取的文件路径
* - options 读取的选项
* - callback 回调函数,通过回调函数将读取的内容返回(err, data)
* err 错误对象
* data 读取到的数据
* 4.流式文件的读取
*
*/
var fs = require("fs")
// 简单文件读取
// fs.readFile("h3.txt",(err, data)=>{
// if(!err)
// console.log(data.toString())
// })
// 流式文件读取
var fs = require("fs")
// 创建一个可读流
var rs = fs.createReadStream("q_2.jpg")
// 创建一个可写流
var ws = fs.createWriteStream("q_2.jpg")
// 监听流的开启和关闭
rs.once("open", ()=>{
console.log("可读流打开了")
})
rs.once("close", ()=>{
console.log("可读流关闭了")
// 关闭可写流
ws.end()
})
ws.once("open", ()=>{
console.log("可写流打开了")
})
ws.once("close", ()=>{
console.log("可写流关闭了")
})
// 如果要读取一个可读流中的数据,必须要为可读流绑定一个data事件,
// data事件绑定完毕,他会自动开始读取数据,读取之后会自动关闭
rs.on("data", (data)=>{
console.log(data)
ws.write(data)
})
var fs = require("fs")
// 创建一个可读流
var rs = fs.createReadStream("q_2.jpg")
// 创建一个可写流
var ws = fs.createWriteStream("q_21.jpg")
// 监听流的开启和关闭
rs.once("open", ()=>{
console.log("可读流打开了")
})
rs.once("close", ()=>{
console.log("可读流关闭了")
})
ws.once("open", ()=>{
console.log("可写流打开了")
})
ws.once("close", ()=>{
console.log("可写流关闭了")
})
// pipe()可以将可读流中的内容,直接输出到可写流中
rs.pipe(ws)
验证路径是否存在
获取文件信息
fs.stat(path, callback)-
fs.statSync(path)
删除文件
列出文件
fs.readdir(path[, options], callback)
fs.readdirSync(path[, options])
截断文件
建立目录
删除目录
重命名文件和目录
监视文件更改写入
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) {
/**
stats.size
stats.isFile()
stats.isDirectory()
stats.isBlockDevice()
stats.isCharacterDevice()
stats.isSymbolicLink()(仅对fs.lstat()有效)
stats.isFIFO()
stats.isSocket()
*/
console.log(stat);
});
/**
* fs.unlink (path, callback )
* fs.unlinkSync(path)
* -删除文件
*/
fs.unlinkSync("hello.txt");
/*
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", 10);
/*
fs.mkdir(path[, mode] , callback )
fs.mkdirSync(path [ , mode] )
- 创建一个目录
fs.rmdir(path, callback )
fs.rmdirSync(path)
- 删除一个目录
*/
// 创建一个文件夹
fs.mkdirSync("hello");
// 删除一个文件夹
fs.rmdirSync("hello");
/*
fs.rename (oldPath, newPath, callback )
fs.renameSync(oldPath, newPath)
-对文件进行重命名
- 参数:
oldPath 旧的路径
newPath 新的路径
callback回调函数
*/
fs.rename("a.mp3", "笔记.mp3", function (err) {
if (!err) {
console.log("修改成功")
}
})
/*
fs.watchFile(filename[ , options] , listener)
-监视文件的修改
-参数:
filename要监视的文件的名字
options配置选项
listener回调函数,当文件发生变化时,回调函数会执行
在回调函数中有两个参数:
curr 当前文件的状态
prev 修改前文件的状态
这两个对象都是stat对象
*/
fs.watchFile("hello2.txt",{interval:1000}, function (curr, prev) {
console.log("文件发生变化了~~~");
console.log("修改前文件大小:",prev.size)
console.log("修改后文件大小:",curr.size)
});