文章目录
关于node.js。我再前面项目中使用webpack搭建项目的时候有了解过。当时单纯只是说配置webpack和vue的时候需要。而没有真正的把它作为一个新的知识点来学习。其实现在node.js对于前端来说还是蛮重要的,还是要慢慢学习啊。
前面有文章介绍node.js的安装,这里就不再重新演示安装了。学习都需要自己动手去撸代码,光看不练假把式。
安装 (略)
node命令
我们在安装node之后,就可以直接在控制台开始操作了。
node -v 查看node的版本
而我们在cmd中也可以直接用node运行我们得代码,像下面这样:
node
console.log('hello word!')
这样我就简单的看到了node展示出来的效果。
当然,除了这种简单的,我们还可以放一个函数在上面就像下面这样:
我们除了可以在直接在node里面运行代码,我们还可以用node运行文件。目前我只尝试过js文件。我在users\Administrator下面新建了一个server.js
内容如下
然后使用
node server.js 运行该文件
我们在网页上打开http://127.0.0.1:8888可以看到页面上已经有了输出内容
REPL
REPL(交互式解释器),可以执行以下任务:
读取 - 读取用户输入,解析输入了Javascript 数据结构并存储在内存中。
执行 - 执行输入的数据结构
打印 - 输出结果
循环 - 循环操作以上步骤直到用户两次按下 ctrl-c 按钮退出。
即我们上面直接在node里面运行代码的实例;
直接运行node,然后在后面直接输入运行代码,我觉得这和浏览器控制台的效果是相同的(个人理解)。
node
简单的表达式运算
>1+2
3
>5-4
1
变量操作
>var x=10
undefined
>y=11
11
>x+y
21
>console.log("hello word")
hello word
undefined
多行表达式
下划线(_)变量
>x=10;
10
>x+13
23
>_
23
我们总结一下REPL命令
REPL 命令(引用node链接)
ctrl + c - 退出当前终端。
ctrl + c 按下两次 - 退出 Node REPL。
ctrl + d - 退出 Node REPL.
向上/向下 键 - 查看输入的历史命令
tab 键 - 列出当前命令
.help - 列出使用命令
.break - 退出多行表达式
.clear - 退出多行表达式
.save filename - 保存当前的 Node REPL 会话到指定文件
.load filename - 载入当前 Node REPL 会话的文件内容。
回调函数
需要多看几遍
事件循环
需要再看几遍
Buffer(缓冲区)
需要在看几遍
stream流
关于文件的读取,在前端我在接触之前一个项目的时候,接触过文件流的传递,不然我一直会觉得文件的读取和前端的关系不大。关于文件的读写,学习之后觉得自己还是在前端缺太多了。
首先我们需要先了解在node中,stream有哪几种状态。
Readable-可读操作
Writable-可写操作
Duplex-可读可写操作
Transform-操作被写入数据,然后读出结果
由于Stream对象都是EventEmitter的实例。常用事件有:
data-当有数据可读时触发
end-没有更多的数据可读时触发
error-在接收和写入过程中发生错误时触发
finish-所有数据已被写入到底层系统时触发
读取文件内容代码:
var fs = require("fs");
var data="";
//创建可读流
var readStream=fs.createReadStream("input.txt");
readStream.setEncoding("UTF8");
readStream.on("data",function(str){
data+=str;
});
readStream.on("end",function(){
console.log(data);
})
readStream.on("error",function(err){
console.log(err.stack)
});
console.log("程序执行完毕");
打印效果如下图:
可写入文件代码
var fs=require("fs");
var data = 'sfasfasfasfasffffffffffffffffffffffffffff';
var writeStream = fs.createWriteStream("output.txt");
writeStream.write(data,'UTF8');
writeStream.end();
writeStream.on("finish",function(){
console.log("写入成功。")
})
console.log("程序执行完成。")
重新打开output.txt文件,可看到我们已经将内容写入成功。
从一个文件读取内容复制到另外一个文件。现在我们知道input.txt和output.txt文件内容不同,现在我想要直接读input.txt的内容到output.txt文件中。
var fs = require("fs");
var readStream = fs.createReadStream('input.txt');
var writeStream = fs.createWriteStream('output.txt');
readStream.pipe(writeStream);//pipe是管道读写操作,直接读取readStream的内容写到writeStream文件中。
console.log("程序完成!!")
我们可以看出此时input.txt和output.txt文件内容已经完全相同。我们已经完成了文件内容的复制。
我们可以在上述情况下,做一个从input.txt文件复制内容,但是保留output.txt文件的原本内容。
我们先来看看连个文件的内容。
var data="";
var readStream = fs.createReadStream('input.txt');
var readStream1 = fs.createReadStream('output.txt');
readStream1.on("data",function(str){
data+=str;
});
readStream.on("data",function(str){
data+=str;
});
readStream.on("end",function(){
var writeStream = fs.createWriteStream('output.txt');
writeStream.write(data,"UTF8")
})
console.log('操作结束!')
执行这段代码之后,我们再来看看两个文件的内容
可以看到这这次的文件内容复制不是直接覆盖,而是将两个文件的内容整合在一起了。不过我觉得上面那个代码还有可优化的空间。不会是这么生硬的写法吧。
注意:fs.createWriteStream(‘output.txt’)之后,output.txt的文件内容就变成空了。
文件压缩
我们在上面了解到了管道流操作,可以读写文件。链式流是通过连接输出流到另外一个流并创建多个流操作链的机制。链式流一般用于管道操作。
下面我们简单的来压缩一个文件。
var fs = require("fs");
var zlib = require("zlib");
fs.createReadStream('output.txt').pipe(zlib.createGzip()).pipe(fs.createWriteStream('output.txt.gz'));
console.log("压缩成功!")
代码执行成功之后,我们就可以看到在output文件的旁边生成了一个output.txt的压缩包。
下面我们将原本的output.txt文件删除。然后对output.txt.giz文件进行解压
var zlib = require('zlib');
fs.createReadStream('output.txt.gz')
.pipe(zlib.createGunzip())
.pipe(fs.createWriteStream('output.txt'));
console.log("文件解压成功!")
这样我们就可以看到output.txt文件又出现啦,压缩,解压的过程就是如此soeasy。
模块系统
在node.js中提供了两个对象,exports 和require。exports 是模块公开暴露的接口。require则是在外部获取一个模块的接口,即获取模块的exports;
node.js里面存在4类模块(原生模块和3中文件模块)
从文件模块缓存中加载
我们可以看出各个模块加载的优先级略有不同。但是都会优先从文件模块的缓存中加载已经存在的模块。
从原生模块中加载
原生模块的优先级仅次于文件模块缓存的优先级。优先检查模块是否在原生模块列表中。原生模块也有一个缓存区,同样也是优先从缓存区加载,如果缓存区没有被加载过,则调用原生模块的加载方式进行加载和执行。
从文件加载
当文件模块缓存不存在,而且也不是原生模块的时候。node.js会解析require方法传入的参数。并从文件系统中加载实际的文件。
require方法接受以下几种参数的传递:
http、fs、path等,原生模块。
./mod或../mod,相对路径的文件模块。
/pathtomodule/mod,绝对路径的文件模块。
mod,非原生模块的文件模块。
node.js函数
在js中,我们可以定义一个函数作为另一个函数的参数。
路由
全局对象
还需要多看
node.js的全局对象是global,所有变量(除了global本身之外),都是global对象的属性。我们在node.js中能能够直接访问到的对象通常都是global的属性,如console,process等,下面会继续介绍。
全局变量与全局对象
global最根本的作用是作为全局变量的宿主。按照ECMAScript的定义,全局变量需满足下面条件;
- 在最外层定义的变量;
- 全局对象属性;
- 隐式定义的变量。
当你定义一个全局变量时,这个变量同时也会成为全局对象的属性。
注意:应当永远使用var定义变量以避免引入全局变量,因为全局变量会污染命名空间,提高代码的耦合风险。
process是一个全局对象,即global对象的属性。
它是用于描述当前node.js进程状态的对象,提供了一个与操作系统的简单接口。
node.js全局对象
常用工具-util
util.inherits()是一个实现对象间原型继承的函数。
util.inherits(constructor,superConstructor);
文件系统
node导入文件系统模块(fs)语法:
var fs = require("fs");
同步和异步读取文件。
node.js文件系统米块中的方法均有同步和异步的版本,例如读取文件内容的函数就有异步fs.readFileSync()和同步fs.readFile();
异步方法函数的最后一个参数为回调函数,回调函数的第一个参数包含了错误信息。建议使用异步方法。性能高效,速度快,无阻塞。
var fs = require("fs");
//异步读取效果
fs.readFile("input.text",function(err,data){
if(err){
console.log(err)
};
console.log("异步读取:"+data.toString())
})
//同步读取
var data=fs.readFile("output.txt");
console.log("同步读取:"+data.toString());
console.log("程序执行完毕")
}
我们可以看到同步获取的数据是在程序执行完之前的读取完毕的,而异步的读取结果却是在程序执行完之后才执行的。
由于之前进行的管道赋值操作,我的input.txt和output.txt的文件内容是一样。
我们可以看出异步和同步的执行顺序的不同
打开文件
open(不过这个打开文件和我想象中的不太一样,我以为可以直接打开文件,像下面这样)
(结果和我想象中有些出入,它是这样的)
嗯?好吧,可能确实是我想太多。
我们用node.js打开文件,代码如下:
var fs = require("fs");
console.log("准备打开文件")
fs.open('input.txt','rs',function(err,fd){
console.log(fd);
console.log("打开文件")
})
下面我们来了解一下open的参数(此地参考菜鸟教程):
fs.open(path, flags[, mode], callback)
- path:是指文件路径
- flags:是指打开文件的方式
- mode : 设置文件模式(权限),文件创建默认权限为 0666(可读,可写)。
- callback:回调函数,带有两个参数如:callback(err, fd)。
flags的参数值可以是以下值:
Flag | 描述 |
---|---|
r | 以读取模式打开文件。如果文件不存在抛出异常 |
r+ | 以读写模式打开文件。如果文件不存在抛出异常。 |
rs | 以同步的方式读取文件。 |
rs+ | 以同步的方式读取和写入文件。 |
w | 以写入模式打开文件,如果文件不存在则创建。 |
wx | 类似 ‘w’,但是如果文件路径存在,则文件写入失败。 |
w+ | 以读写模式打开文件,如果文件不存在则创建。 |
wx+ | 类似 ‘w+’, 但是如果文件路径存在,则文件读写失败。 |
a | 以追加模式打开文件,如果文件不存在则创建。 |
ax | 类似 ‘a’, 但是如果文件路径存在,则文件追加失败。 |
a+ | 以读取追加模式打开文件,如果文件不存在则创建。 |
ax+ | 类似 ‘a+’, 但是如果文件路径存在,则文件读取追加失败。 |
获取文件信息
fs.stat(path,callback);
-
path是文本路径
-
callback是回调函数,带有两个参数如:(err, stats), stats 是 fs.Stats 对象。
var fs = require("fs"); fs.stat('input.txt',function(err,stats){ console.log(stats); })
我们可以获取这部分文件的数据。
当然我们也可以通过stat提供的方法判断文件的一些属性(参考菜鸟教程):
方法 | 描述 |
---|---|
stats.isFile() | 如果是文件返回 true,否则返回 false。 |
stats.isDirectory() | 如果是目录返回 true,否则返回 false。 |
stats.isBlockDevice() | 如果是块设备返回 true,否则返回 false。 |
stats.isCharacterDevice() | 如果是字符设备返回 true,否则返回 false。 |
stats.isSymbolicLink() | 如果是软链接返回 true,否则返回 false。 |
stats.isFIFO() | 如果是FIFO,返回true,否则返回 false。FIFO是UNIX中的一种特殊类型的命令管道。 |
stats.isSocket() | 如果是 Socket 返回 true,否则返回 false。 |
写入文件
fs.writeFile(file,data[,options],callback)
参数说明
-
file:文件名或文件描述符
-
data:要写入文件的数据,可以是string字符串或buffer缓冲对象。
-
options:该参数是一个对象,包含{encoding,mode,flag}。默认编码为utf8,模式为0666,flag为‘w’(该模式下直接覆盖源文件内容)
-
callback:回调函数,回调函数只包含错误信息参数(err),在写入失败时调用。
fs.writeFile('input.txt','一二三四一二三四想收个,老板、是色均有绿色均有教会我',function(err){ if(err){ return console.err(err); } })
此时我们已经替换了input.txt中的内容。
读取文件
fs.read(fd,buffer,offset,length,psition,callback)
该方法使用了文件描述符来读取文件
参数使用如下(参考菜鸟教程):
-
fd:通过fs.open()方法来返回文件描述符
-
buffer:数据写入的缓冲区
-
offset:缓冲区写入的写入偏移量
-
length:要冲文件中读取的字节数
-
position:文件读取的起始位置,如果position的位置为null,则会从当前文件指针的位置读取。
-
callback:回调函数,有三个参数err,bytesRead,buffer,err为作为信息,bytesRead表示读取的字节数,buffer为缓冲区对象。
var buf = new Buffer.alloc(1024); console.log("准备打开文件"); fs.open("input.txt","r",function(err,fd){ if(err){ return console.err(err); } console.log("打开文件。"); console.log("准备读取文件"); fs.read(fd,buf,0,buf.length,0,function(err,btyes){ console.log("读取文件内容") if(err){ return console.err(err) }; console.log(btyes+"个字节被读取"); if(btyes>0){ console.log(buf.slice(0).toString()) } }) }) console.log("程序执行结束。")
我们就顺利的通过了fs.read方法读取了文件内容。
关闭文件
fs.close(fd,callback)
参数说明
- fd:fs.open()方法返回的文件描述
- callback:回调函数,没有参数,可返回err错误提示
截取文件
fs.fteuncate(fd,len,callback);//该方法使用了文件描述符来读取文件
参数使用说明:
- fd:通过fs.open()方法返回的文件描述符
- len:文件内容截取长度
- callback:回调函数,没有带参数
其实我们前面了解到的read也可以只读取一部分文件内容。fs.read(fd,buffer,offset,length,psition,callback)控制length长度就可以只读取文件的一部分
删除文件
fs.unlink(path,callback)
参数说明:
- path:文件路径
- callback:回调函数,没有参数
创建目录
fs.mkdir(path[,options],callback)
参数说明:
-
path:文件路径
-
options:参数可以是:
- recursive:是否以递归的方式创建目录,默认为false。
- mode:设置目录权限,默认为 0777。
-
callback:回调函数,没有参数
fs.mkdir('newObject/',function(err){ if(err){ return console.err(err); } console.log("创建目录成功"); })
我们可以看到newObject文件夹就创建成功了,说明目录创建成功。当我们创建已存在的目录时,就会出现报错
读取目录
fs.readir(path,callback)
参数说明:
- path:文件路径
- callback:回调函数,回调函数带有err,files。err为错误信息,files为目录下的文件数组列表
我们在刚刚新建的newObject里面新增一些内容。
然后执行下面代码;
fs.readdir("newObject/",function(err,files){
if(err){
console.log(err)
}
console.log(files);
})
我们可以得到如下结果
证明确实拿到了所查询目录下的所有文件。
删除目录
fs.rmdir(path,callback);
参数说明:
- path:文件路径
- callback:回调函数,没有参数
除了我们上面介绍到的模块方法,我们还有其他文件的模块方法。在这里直接引用菜鸟教程的模块方法参考手册
文件模块方法参考手册。进入链接之后可直接f3查询 文件模块方法参考手册 以方便直接定位