cnpm init –yes 强制启动
简介
Commonjs
规范的提出,弥补javascript
没有标准的缺陷,提供一个类似后端语言的标准库,也就是说commonjs
是模块化的标准,nodejs
就是commonjs
模块化的实现。在nodejs中http,url,fs等等都是nodejs的内置模块,可以直接使用。commonjs
中自定义模块的实现:
在nodejs
中将公共的功能抽离为单独的js文件作为模块,在外部是没有办法访问的(类似后端的私有的属性和方法);- 要想使用模块,就必须在模块里面通过
exports
或者module.exports
暴露属性或者方法。在需要的模块使用require
引入模块。
使用
- 新建app.js文件,因为默认启动时加载的是app.js文件。
接口暴露方法:
export default http
或者module.export = http;
//1. 发送请求
const http = require("http");
const url = require("url");
http.createServer((req, res) => {
if (req.url != "/favicon.ico") {
let path = url.parse(req.url,true);
let query=path.query;
console.log(path.query);
res.writeHead(200, { "Content-Type": "text/html;charset=utf-8" });
// 响应的数据
res.write("解析路径传值:"+JSON.stringify(query));
res.end();
}).listen(8080, "localhost", () => {
console.log("creat success");
})
//接口暴露
module.export=http;//或者使用 export default http
- 在自定义的外部文件中如果想使用app.js里的接口,
require
请求,通过相对路径引入暴露的接口let server=require('app');
怎样require直接使用(自定义)文件名,像使用本地接口直接
let url =require('url')
,不用写明相对路径?
解决:
nodejs
可以自动找node_modules
文件下的文件,将自己的代码封装在node_modules目录下的文件里,在外部文件中就可以通过文件名请求
步骤:函数暴露示例
cnpm init
启动cnpm ,根据自己的情况选择合适选项
执行后目录下出现package.json文件
- 我把上文代码中的请求服务函数内容封装在了node_modules下的新文件
createServer
中(并给这个方法配置他需要的模块)
const url = require("url");
module.exports=(req,res)=>{
if (req.url != "/favicon.ico") {
let path = url.parse(req.url,true);
let query=path.query;
console.log(path.query);
// 响应头的编码格式
res.writeHead(200, { "Content-Type": "text/html;charset=utf-8" });
// 响应的数据
res.write("解析路径传值:"+JSON.stringify(query));
res.end();
}
}
- 这样就可以简化
server
里的代码,因为将方法暴露出去,所以再使用时require(‘文件名’)
引入就可使用
//1. 发送请求
const http = require("http");
let server=require('createServer'); //直接通过名称引入
//2. 使用api的方法 创建服务器(请求服务)
http.createServer(server).listen(8080, "localhost", () => {//使用封装在米快里的方法server
console.log("creat success");
})
对象暴露
- 在node_modules下新建
getData.js
,并将对象暴露出去
let stu=[
{
"name":"张三",
"sex":"男",
"age":18
},
{
"name":"李四",
"sex":"男",
"age":23
},
{
"name":"五三",
"sex":"男",
"age":22
},
]
module.exports=stu;
- 在
node_modules
下的createServer.js
里请求数据
let stu = require('../model/getUserData');
- 输出数据测试即可
const url = require("url");
let stu = require('../model/getUserData');
//加载文件流模块
let stream = require('../model/filestream');
module.exports = (req, res) => {
if (req.url != "/favicon.ico") {
let path = url.parse(req.url, true);
let query = path.query;
console.log(path.query);
// 响应头的编码格式
res.writeHead(200, { "Content-Type": "text/html;charset=utf-8" });
// 响应的数据
console.log(stu);
res.write("解析路径传值:" + JSON.stringify(stu));
res.end();
}
}
后台模拟操作数据库增删改查的封装方法
//模拟操作数据库的增删改查
let connection=(callback)=>{
//连接数据库
}
//封装方法二
module.exports.insertData=(res)=>{
connection(()=>{
});
}
//封装方法三 自执行函数
modulu.exports=(()=>{
})();
//es6类封装
class mysql{
constructor(){
}
insert(){
}
updata(){
}
delete(){
}
}
加密解密
md5-node包 单向加密
- 安装
cnpm install md5-node –save-dev
安装完之后项目里面生成一个node_modules依赖文件 - 使用:
//单向加密模块 不能解密
let md5 = require('md5-node')
base64 双向加密模块
- 安装
cnpm install –-save-dev js-base64
安装完之后项目里面生成一个node_modules依赖文件 - 使用:
一定要
.Base64
//双向加密模块
let base = require('js-base64').Base64
//base64
let test = base.encode(JSON.stringify(stu));//encode加密
console.log(test);
let str = base.decode(test);//decode 解密
console.log(str);
文件流系统
- 文件流模块 fs 是node的内置模块
- 文件读写等操作
- fs中的方法分为同步或异步
- __dirname 是当前文件的相对上级目录
例如下图:console.log(__dirname ); // D:\node\Mystudy1\model
mode
- 文件创建默认权限为0666
(可读,可写)。设置目录权限,默认为0777
(可读可写可执行)。
- 新建文件
filestream.js
//引入文件模块 let fs=require('fs')
- 暴露接口(以函数方法)
1. 文件读取
异步读取文件(已经新建了静态资源文件目录,新建文本文档txt:这是我的一小段测试文字)
Buffer
:一个缓冲池
module.exports=()=>{
console.log("文件流系统正在运行");
//1. 异步读取文件
fs.readFile("public/test.txt",(err,data)=>{
if(err){
throw err;
}
console.log(data);//<Buffer e8 bf 99 e6 98 af e6 88 91 e7 9a 84 e4 b8 80 e5 b0 8f e6 ae b5 e6 b5 8b e8 af 95 e6 96 87 e5 ad 97 0d 0a>
});
}
结果输出数据为16进制码,在上段代码中加修改,需要转换成字符串后输出
tostring
里的格式和源文件一致即可
console.log(data.toString('utf-8')); //这是我的一小段测试文字
- 同步读取文件
//2. 同步读取文件
let tb=fs.readFileSync("public/test.txt",'utf-8');
console.log(tb);
异步读取和同步读取的区别:异步读取文件的时候由操作系统在后台进行读取,不会阻碍下面的代码执行。同步读取的时候会阻碍下面的代码执行。
let fs = require('fs') //获取fs模块
module.exports = () => {
//1. 异步读取文件
console.log("异步读取start");
fs.readFile("public/test.txt", (err, data) => {
//读取文件,回调函数第一个参数表示错误信息,第二个参数为读取的文本内容
if (err) {
throw err;
}
else {
console.log("异步读取end");
console.log(data.toString('utf-8'));
}
});
//2. 同步读取文件
console.log("同步读取start");
let tb = fs.readFileSync("public/test.txt", 'utf-8');
console.log(tb);
console.log('同步读取end');
}
输出结果为:
可见:异步读取开始、同步读取开始、同步读取结束、异步读取结束。
异步读取没有结束,同步读取就完成了。
结论:异步读取没有阻塞下面代码的执行。
2. 打开文件
2.1 异步打开文件
同步和异步的区别上文已经提过
- 格式
fs.open(path, flags , [mode], callback)
- 参数含义
path
- 文件的路径。
flags
- 文件打开的行为。
mode
- 设置文件模式(权限),文件创建默认权限为 0666(可读,可写)。
callback
- 回调函数,带有两个参数如:callback(err, fd)。
- 实例
我们在之前创建的filestream.js
文件里打开test.txt
文件进行读写
let fs = require("fs");
//异步打开文件
fs.open("public/test.txt", 'r+', (err, fd) => {
if (err) {
console.log("文件打开失败");
throw err;
}
console.log("当前文件已打开");
});
执行结果为:
当前文件已打开
2.2 同步打开文件(不常用)
//同步打开文件
let tb=fs.openSync("public/test.txt", 'r+');
console.log(tb);
返回值为随机数字时说明返回成功
3. 获取文件信息
- 格式(异步)
fs.stat(path, callback)
- 参数含义
path
- 文件路径。
callback
- 回调函数,带有两个参数如:(err, stats)
, stats 是fs.Stats
对象。
- 实例
fs.stat("public/test.txt", (err, stats) => {
if (err) {
console.log("文件打开失败");
throw err;
}
console.log(stats.isFile());//true
});
4. 写入文件
当前写入内容会覆盖文件原有内容
4.1 异步
fs.writeFile("public/test.txt", "这是我写入的数据", (err) => {
if (err) {
throw err;
}
});
直接追加到文件中的写入方法不会覆盖原有的内容
fs.appendFile ("public/test.txt", "再一次写入看看会不会覆盖", (err) => {
if (err) {
throw err;
}
});
4.2 同步
//同步
fs.writeFileSync("public/test.txt","这是我同步写入的数据");
5. 读取文件
- 不断地将文件中的一小块内容读入缓存区,最后从该缓存区中读取文件内容
- 一个汉字或中文字符3个字节,英文字母或符号1个字节
- 什么是文件描述符fd?
文件描述符(file descriptor)在形式上是一个非负整数。实际上,它是一个索引值,每一个文件描述符会与一个打开文件相对应。
- 语法
该方法使用了文件描述符来读取文件。
fs.read(fd, buffer, offset, length, position, callback)
- 参数
fd
- 通过fs.open()
方法返回的文件描述符。
buffer
- 数据写入的缓冲区。
offset
- 缓冲区写入的写入偏移量。
length
- 要从文件中读取的字节数。
position
- 文件读取的起始位置,如果position
的值为null
,则会从当前文件指针的位置读取。
callback
- 回调函数,有三个参数err, bytesRead, buffer
,err
为错误信息,bytesRead
表示读取的字节数,buffer
为缓冲区对象。
- 底层源码:
fs.read = function(fd, buffer, offset, length, position, callback) {
if (!util.isBuffer(buffer)) {
// legacy string interface (fd, length, position, encoding, callback)
var cb = arguments[4],
encoding = arguments[3];
assertEncoding(encoding);
position = arguments[2];
length = arguments[1];
buffer = new Buffer(length);
offset = 0;
callback = function(err, bytesRead) {
if (!cb) return;
var str = (bytesRead > 0) ? buffer.toString(encoding, 0, bytesRead) : '';
(cb)(err, str, bytesRead);
};
}
function wrapper(err, bytesRead) {
// Retain a reference to buffer so that it can't be GC'ed too soon.
callback && callback(err, bytesRead || 0, buffer);
}
binding.read(fd, buffer, offset, length, position, wrapper);
};
- 实例
let buffer = new Buffer(500);
//异步打开文件
fs.open("public/data.txt", 'r+', (err, fd) => {
if (err) {
throw err;
}
fs.read(fd, buffer, 0, buffer.length, 0, (err, bytes) => {
if (err) {
console.log(err);
}//读取出来的数据存放在buffer中
fs.writeFile("public/test.txt", buffer.toString("utf-8"), (err) => {
if (err) {
throw err;
}
console.log("写入成功");
});
});
});
6. 关闭文件
- 语法(异步)
fs.close(fd, callback)
- 参数
fd
- 通过fs.open()
方法返回的文件描述符。
callback
- 回调函数,没有参数。
- 实例
//文件关闭
fs.open("public/data.txt", 'r+', (err, fd) => {
if (err) {
throw err;
};
console.log("文件打开成功!");
fs.close(fd,(err)=>{
if (err) {
throw err;
};
console.log("文件关闭成功");
});
});
7. 截取文件
- 语法(异步模式)
fs.ftruncate(fd, len, callback)
- 参数
fd
- 通过fs.open()
方法返回的文件描述符。
len
- 文件内容截取的长度。
callback
- 回调函数,没有参数。
- 实例
//存储截取后的字符
let buffer = new Buffer(1024);
//打开文件
fs.open("public/test.txt", 'r+', (err, fd) => {
if (err) {
throw err;
};
//截取文件
fs.ftruncate(fd, 100, (err) => {
if (err) {
throw err;
};
console.log("文件截取成功");
});
//读取截取后的文件
fs.read(fd, buffer, 0, buffer.length, 0, (err, bytes) => {
if (err) {
console.log(err);
}
console.log(buffer.toString('utf-8'));
});
//关闭文件
fs.close(fd,(err)=>{
if(err){
throw err;
}
});
});
8.删除文件
- 语法(异步)
fs.unlink(path, callback)
- 参数
path
- 文件路径。
callback
- 回调函数,没有参数。
- 实例
fs.unlink("public/data.txt",(err)=>{
if(err){
throw err;
}
console.log("文件删除成功!");
});
9.创建目录
- 语法
fs.mkdir(path, [options], callback)
- 参数
path
- 文件路径。
options
参数可以是:
recursive
- 是否以递归的方式创建目录,默认为 false。
mode
- 设置目录权限,默认为0777
。
callback
-> 回调函数,没有参数。
- 实例
// 创建目录
fs.mkdir("public/${testname}",(err)=>{
if(err){
throw err;
}
console.log("文件创建成功");
});
//反编译绑定文件名
let testname="zmttesttwo";
fs.mkdir(`public/${testname}`,(err)=>{ //注意反编译的写法 没有双引号!
if(err){
throw err;
}
console.log("文件创建成功");
});
10.读取目录
- 语法
fs.readdir(path, callback)
- 参数
path
- 文件路径。
callback
- 回调函数,回调函数带有两个参数err
,files
err 为错误信息,files 为 目录下的文件数组列表。
- 实例
fs.readdir("public", (err, files) => {
if (err) {
console.log(err);
}
console.log(files);//[ 'test.txt', 'zmtTest', 'zmttesttwo' ]
//遍历数组输出
files.forEach((file) => {
console.log(file);
});
});
- 读取固定目录,判断里面的所有子目录是文件还是文件夹:
//递归遍历目录里面的每一层
let pathinfo = "public"
let method = (path) => {
fs.readdir(path, (err, files) => {
if (err) {
throw err;
}
//遍历子目录
files.map((value, index) => {
fs.stat(path + `/${value}`, (error, stats) => {
if (error) {
throw error;
}
//开始判断是否是目录还是文件
if (stats.isFile()) {
console.log(value + "是文件");
}
else if (stats.isDirectory()) {
console.log(value + "是目录");
method(path + `/${value}`);
}
});
});
});
}
method(pathinfo);
11.删除目录
- 语法
区分此方法(删除目录)和删除单文件
unlink
fs.rmdir(path, callback)
- 参数
path
- 文件路径。
callback
-> 回调函数,没有参数。
- 实例
fs.rmdir("public/zmtTest",function(err){
if (err) {
return console.error(err);
}
console.log("读取 /public 目录");
//读取删除后的文件
fs.readdir("public/",function(err, files){
if (err) {
return console.error(err);
}
files.forEach( function (file){
console.log( file );
});
});
});
优化:检测目录
检测文件是否存在
fs.exists("public/zmt", (exist) => {
//如果文件不存在
if (!exist) {
// 创建目录
fs.mkdir("public/zmtTest", { mode: 0777 }, (err) => {
if (err) {
throw err;
}
console.log("文件创建成功");
});
} else {
console.log("该文件存在");
}
//执行相关操作 如添加子目录写入内容等
fs.appendFile("public/zmtTest/addfile", "我正在写入内容!", (err) => {
if (err) {
throw err;
}
console.log('写入成功');
});
});