Node.js
下载和环境变量
下载
下载地址
windows
下直接下载.msi
安装包,环境变量会自动配好。
环境变量配置
查看环境变量是否配置
打开cmd
输入node
,若可以运行则已配置
配置环境变量
将node
安装目录添加到path
,例如C:\Program Files\nodejs\
创建Node.js应用
基础示例:
test.js:
var http=require('http'); //require是Node.js自带的http模块
http.createServer(function(request,response){
response.writeHead(200,{'Content-Type':'text/html;charset=UTF-8'}); //状态码200-OK,中文编码
response.end('<p style="color:red">你好</p>');
}).listen(8888); //指定服务端口
console.log("Server running...");
运行
cmd
内运行:
node test.js
Server running...
不要关闭cmd
窗口,可以通过http://localhost:8888/
访问服务器返回的数据
关闭cmd
窗口后,服务即停止
NPM使用(not ok)
NPM(Node.js Package management)
用来管理Node.js
包,可以从NPM服务器下载别人或上传自己的第三方包和命令行程序
NPM
随Node.js
一同安装,环境变量同Node.js
目录
升级NPM
npm install npm -g //官方镜像
npm install -g cnpm --registry=https://registry.npm.taobao.org //国内淘宝镜像
安装/卸载/更新模块
例如express
:
npm install express //本地,安装
npm install express -g //全局,安装
通过npm
安装的本地模块存放在运行npm
的目录下的node_modules
子目录下
通过npm
安装的全局模块存放在node
安装目录下的node_modules
子目录下
npm uninstall express //本地,卸载
npm uninstall express -g //全局,卸载
npm update express //本地,更新
npm update express -g //全局,更新
查看已安装的模块
npm list //本地,查看所有
npm list --global //全局,查看所有
npm list -g //全局,简写,查看所有
npm list accepts //本地,已知模块名查看版本
npm list open -g //全局,已知模块名查看版本
npm list --depth=0 //本地,指定深度,默认全部,0为不显示依赖包,1为仅显示一层依赖包,2...
npm list -g --depth=0 //全局,指定深度
模块package.json
package.json
位于\node_modules\包名\
下,这里用express
模块的package.json
作为示例:
{
/*包名*/ "name": "express",
/*包版本*/ "version": "4.17.1",
/*包描述*/ "description": "Fast, unopinionated, minimalist web framework",
/*包官方地址*/ "homepage": "http://expressjs.com/",
/*包作者*/ "author": {/*... ...*/},
/*其他贡献者*/ "contributors": [{/*... ...*/},{/*... ...*/}],
/*依赖包*/ "dependencies": {"accepts": "~1.3.7","array-flatten": "1.1.1"/*... ...*/},
/*项目托管地址*/ "repository":{"type":"git","url":"git+https://github.com/expressjs/express.git"},
/*关键字*/ "keywords": ["express","framework"/*... ...*/}
/*... ...*/
}
REPL
REPL
(Read Eval Print Loop
:交互式解释器),类似windows
的cmd
或linux
的shell
,提供交互功能
执行语句
表达式运算
>(1+2)/5
0.6
下划线变量
下划线表示上一个表达式的运算结果
>1+5
6
>a=_
6
js语句
//单行
>var x=5;
undefined
//多行
>if(x>10){
>... console.log('a');
>... }else{
>... console.log('b');
>... }
b
REPL命令
命令 | 操作 |
---|---|
退出 | ctrl+c x2 或 ctrl+d |
历史 | 上/下光标 |
退出多行表达式 | .break 或 .clear |
保存会话 | .save filename (绝对/相对路径均可) |
加载会话 | .load filename (绝对/相对路径均可) |
事件触发器
events
模块提供了EventEmitter
对象,该是事件触发和监听功能的封装
基础示例
var events=require("events");
var emitter=new events.EventEmitter();
emitter.on('someEvent',function(arg1,arg2,arg3){ //on:注册监听器
console.log('listener1', arg1, arg2,arg3);
});
emitter.addListener('someEvent',function(){ //addListener:on的别名
console.log('listener2');
});
emitter.emit('someEvent','arg1 参数','arg2 参数'); //emit:事件触发
执行结果为:
listener1 arg1 参数 arg2 参数 undefined
listener2
- 可以创建多个名称相同的监听器,这些监听器按书写顺序依次执行
- 触发某个名称的监听器时,所有该名称的监听器都会被触发,即使参数个数不对应,没有的参数undefined,多的参数抛弃
移除事件
方法 | 作用 |
---|---|
removeListener(event,lisntener) | 移除指定名称事件的某个事件 |
removeAllListeners(event) | 移除指定名称事件的所有事件 |
removeAllListeners() | 移除所有名称事件的所有事件 |
var events=require("events");
var emitter=new events.EventEmitter();
var fun1=function(){
console.log('listener1');
}
var fun2=function(){
console.log('listener2');
}
emitter.on('someEvent',fun1);
emitter.on('someEvent',fun2);
emitter.on('someEvent2',fun1);
emitter.on('someEvent2',fun2);
emitter.emit('someEvent');
emitter.emit('someEvent2');
console.log('-----------------');
emitter.removeListener('someEvent',fun1);
emitter.emit('someEvent');
emitter.emit('someEvent2');
console.log('-----------------');
emitter.removeAllListeners('someEvent');
emitter.emit('someEvent');
emitter.emit('someEvent2');
console.log('-----------------');
emitter.removeAllListeners();
emitter.emit('someEvent');
emitter.emit('someEvent2');
once
var events=require("events");
var emitter=new events.EventEmitter();
emitter.once('someEvent',function(){ //once:仅触发一次
console.log('once listener');
});
emitter.emit('someEvent');
console.log('-----------------');
emitter.emit('someEvent');
结果为:
once listener
-----------------
MaxListeners
某个名称的监听器添加的监听器数量>10
会出警告信息,但不会阻止正常监听或运行,可以通过setMaxListeners(n)
调整
var events=require("events");
var emitter=new events.EventEmitter();
var fun=function(){
console.log('listener');
}
emitter.setMaxListeners(99); //需要在注册监听器前使用
emitter.on('someEvent',fun); //1
emitter.on('someEvent',fun);
emitter.on('someEvent',fun);
emitter.on('someEvent',fun);
emitter.on('someEvent',fun);
emitter.on('someEvent',fun);
emitter.on('someEvent',fun);
emitter.on('someEvent',fun);
emitter.on('someEvent',fun);
emitter.on('someEvent',fun);
emitter.on('someEvent',fun); //11
emitter.emit('someEvent');
listeners
listeners(event)
用于获取指定名称事件的监听器数组
var events=require("events");
var emitter=new events.EventEmitter();
var fun=function(){
console.log('listener');
}
emitter.on('someEvent',fun);
emitter.on('someEvent',fun);
emitter.on('someEvent',fun);
var ls=emitter.listeners('someEvent');
for(var i=0;i<ls.length;i++){
console.log(ls[i]);
}
结果为:
[Function: fun]
[Function: fun]
[Function: fun]
listnerCount
listnerCount
返回指定事件的监听器数量
var events=require("events");
var emitter=new events.EventEmitter();
var fun1=function(){
console.log('listener1');
}
var fun2=function(){
console.log('listener2');
}
emitter.on('someEvent',fun1);
emitter.on('someEvent',fun2);
console.log(emitter.listenerCount('someEvent')); //2
缓冲区
创建缓冲区
//创建一个长度10,以0填充的Buffer
const buf1=Buffer.alloc(10);
console.log(buf1); //<Buffer 00 00 00 00 00 00 00 00 00 00>
//创建一个长度10,以n填充的Buffer
//n(十进制0~255)对应(十六进制00~ff)
const buf2=Buffer.alloc(10,123); //0x123
console.log(buf2); //<Buffer 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b>
//创建一个长度10,未初始化的Buffer
//速度快于alloc
//因为未初始化,所以可能会包含旧数据
const buf3=Buffer.allocUnsafe(10);
console.log(buf3); //示例:<Buffer e0 1c 3b 24 8b 02 00 00 20 20>
//创建一个包含指定数组的Buffer
const buf4=Buffer.from([10,30,55]); //0x10 0x30 0x55
console.log(buf4); //<Buffer 0a 1e 37>
//创建一个包含指定UTF-8字节的Buffer
const buf5=Buffer.from("tést"); //例如t的UTF-8编码对应0x74
console.log(buf5); //<Buffer 74 c3 a9 73 74>
//创建一个包含指定Latin-1字节的Buffer
const buf6=Buffer.from("tést","latin1");
console.log(buf6); //<Buffer 74 e9 73 74>
写入缓冲区(write)
const buf=Buffer.allocUnsafe(10);
console.log(buf); //<Buffer 18 00 7c 00 00 00 10 00 90 00>
l=buf.write("abcde");
console.log(l+" "+buf); //5 abcde����
l=buf.write("fghij",5,3,"utf-8");
/*buf.write(string[,offset[,length]][,encoding])
* offset:从0开始
* length:指定插入的长度,默认为buffer长度(该buffer为10),3表示只插入fgh
* encoding:编码,默认为UTF-8 */
console.log(l+" "+buf); //3 abcdefgh��
读取缓冲区(toString)
const buf=Buffer.from("tést","UTF-8");
console.log(buf.toString("UTF-8",1,3)); //é(该字符占了3位)
/*buf.toString([encoding[,start:开始截取位置[,end]]])
* encoding:使用的编码,默认为UTF-8
* start:开始截取位置,默认为0
* end:结束截取位置,默认位缓冲区末尾 */
转换为JSON(toJSON)
const buf=Buffer.from("tést");
console.log(buf.toJSON());
合并缓冲区(concat)
const buf1=Buffer.from("lo"); //<Buffer 6c 6f>
const buf2=Buffer.from("hel"); //<Buffer 68 65 6c>
var bufs=Buffer.concat([buf2,buf1]);
/*Buffer.concat(list[,totalLength])
* totalLength:合并后的长度,默认为所有者总长度
*/
console.log(bufs); //<Buffer 68 65 6c 6c 6f>
比较缓冲区(compare)
//hel<lo
const buf1=Buffer.from("lo");
const buf2=Buffer.from("hel");
const buf3=Buffer.from("hel");
console.log(buf1.compare(buf2)); //1(前>后)
console.log(buf2.compare(buf1)); //-1(前<后)
console.log(buf3.compare(buf2)); //0(前=后)
拷贝和剪裁缓冲区(copy和slice)
剪裁缓冲区返回的对象与原对象指向同一块内存区域
拷贝缓冲区拷贝了一个一样的对象,并不指向同一块内存区域
//copy:
const buf1=Buffer.from("WORLD");
const buf2=Buffer.from("hello");
buf1.copy(buf2); //buf1-->buf2
console.log(buf2.toString()); //WORLD
const buf3=Buffer.from("H");
const buf4=Buffer.from("text:hello");
buf3.copy(buf4,5,0,1);
/*buf.copy(targetBuffer[,targetStart[,sourceStart[,sourceEnd]]])
* targetStart:被粘贴对象的起始粘贴位置
* sourceStart:拷贝对象的拷贝起点
* sourceEnd:拷贝对象的拷贝终点,默认为该对象总长度
*/
console.log(buf4.toString()); //text:Hello
//slice:
const buf1=Buffer.from("hello");
const buf2=buf1.slice(2,4);
console.log(buf2.toString()); //ll
buf1[2]=78; //返回的对象与原对象指向同一块内存区域
console.log(buf2.toString()); //Nl
获取缓冲区大小(length)
const buf=Buffer.from("héllo");
console.log(buf); //<Buffer 68 c3 a9 6c 6c 6f>
console.log(buf.length); //6
流
输出流(read)
事件名 | 含义 |
---|---|
data | 读取的文件内容不为空时触发 |
end | 文件读取完毕时触发 |
error | 发生错误时触发 |
var fs=require("fs");
var readerStream=fs.createReadStream("a.txt"); //Read输出流
readerStream.setEncoding("UTF-8");
readerStream.on("data",function(chunk){
console.log("数据不为空,内容为:"+chunk);
})
readerStream.on("end",function(){
console.log("读取完毕");
})
readerStream.on("err",function(err){
console.log(err.stack);
})
输入流(write)
注意不是追加,会覆盖源文件
事件名 | 含义 |
---|---|
finish | 写入完毕时触发 |
var fs=require("fs");
var writerStream=fs.createWriteStream("a.txt"); //Write输入流
writerStream.write("world","UTF-8");
writerStream.end(); //标记结束,否则不会触发finish事件,经测试不会影响写入
writerStream.on("finish",function(chunk){
console.log("写入完毕");
})
writerStream.on("err",function(err){
console.log(err.stack);
})
管道流
读取一个文件到另一个文件,被写入的文件被覆盖,称为管道流
用输入流和输出流实现:
var fs=require("fs");
var writerStream=fs.createWriteStream("a.txt"); //hello
var readerStream=fs.createReadStream("b.txt"); //world
readerStream.on("data",function(chunk){
var text=chunk.toString("UTF-8");
writerStream.write(text,"UTF-8");
})
//a.txt --> world
//b.txt --> world
用pipe
实现(等同于上面,更简便):
var fs=require("fs");
var writerStream=fs.createWriteStream("a.txt");
var readerStream=fs.createReadStream("b.txt");
readerStream.pipe(writerStream); //readerStream-->writerStream
链式流
压缩/解压缩示例
使用管道pipe
组成链称为链式流
压缩:
var fs=require("fs");
var zlib=require("zlib");
fs.createReadStream("a.txt")
.pipe(zlib.createGzip()) //a.txt --> 压缩
.pipe(fs.createWriteStream("a.txt.gz")); //压缩 --> a.txt.gz
解压缩:
var fs=require("fs");
var zlib=require("zlib");
fs.createReadStream("a.txt.gz")
.pipe(zlib.createGunzip()) //a.txt.gz --> 解压缩
.pipe(fs.createWriteStream("a.txt")); //解压缩 --> a.txt
模块系统(not ok)
创建和引用
exports.xxx
成员函数封装到模块
dog.js:
exports.say=function(){
console.log("hello,I'm dog");
}
test.js:
var dog=require("./dog");
/*导入js文件(模块)
* 模块名必须和被赋值的变量名相同 */
dog.say();
module.exports
封装整个对象到模块,这种情况下模块内仅包含这一个对象
dog.js:
module.exports=function(){
var name="dog";
this.getName=function(){
console.log("name="+name);
}
}
test.js:
var dog=require("./dog");
dog=new dog();
dog.getName();
路由(not ok)
URL处理模块:url
querystring
url.parse(request.url).query
|
url.parse(request.url).pathname |
| |
| |
/index.html name=sam&age=20
----------- ---------------
localhost:8888/index.html?name=sam&age=20
---
sam
|
querystring.parse(query)["name"]
server.js:
var http=require("http");
var url=require("url");
var querystring=require("querystring");
exports.start=function(route){
http.createServer(function(request,response){
var pathname=url.parse(request.url).pathname;
var query=url.parse(request.url).query;
var name=querystring.parse(query)["name"];
route(pathname+"\n"+query+"\nname="+name); //给路由传参
response.writeHead(200,{'Content-Type':'text/html;charset=UTF-8'});
response.write('你好');
response.end();
}).listen(8888);
console.log("Server started on 8888.")
}
route.js:
exports.route=function(pathname){
console.log("About to route a request for "+pathname);
}
index.js:
var server=require('./server');
var router=require('./router');
server.start(router.route);
全局变量
filename和dirname
变量 | 意义 |
---|---|
__filename | 当前脚本文件名 |
__dirname | 当前脚本所在目录 |
index.js:
var mk=require("./mk");
mk.say();
console.log(__filename); //C:\test\test.js
console.log(__dirname); //C:\test
mk.js:被引用的模块的该变量也正确指向本身
exports.say=function(){
console.log(__filename); //C:\test\mk.js
console.log(__dirname); //C:\test
}
顶级变量
类似js
中的window
,Node.js
也有顶级变量global
顶级变量事件
事件 | 意义 |
---|---|
eixt | 程序结束时触发 |
beforeExit | 程序结束前触发 |
uncaughtException | 捕获异常 |
eixt
和beforeExit
process.on("exit",function(code){
setTimeout(function(){ //该代码不会被运行
console.log("exit异步");
},1000);
console.log("exit,状态码:"+code);
})
process.on("beforeExit",function(code){
setTimeout(function(){ //该代码会被运行
console.log("beforeExit异步");
//process.exit();
},1000);
console.log("beforeExit,状态码:"+code);
})
结果:
beforeExit
中的异步代码被执行,导致程序永远在等待和处于结束前状态,这样程序就不会退出
beforeExit,状态码:0
beforeExit异步
beforeExit,状态码:0
beforeExit异步
... ...
可以在beforeExit
异步代码执行完至后执行process.exit()
,手动结束程序:
beforeExit,状态码:0
beforeExit异步
exit,状态码:0
在这种情况下beforeExit
不会被触发:
process.on("exit",function(code){
console.log("exit");
})
process.on("beforeExit",function(code){
console.log("beforeExit");
})
process.exit();
结果:beforeExit
在没有事件处理时才会触发,但手动提前结束了程序,导致beforeExit
不会被触发
exit
uncaughtException
没有写异常捕获语句,由系统处理,也可以手动处理,系统不会参与处理:
process.on("uncaughtException",function(code){
console.log("异常:"+code);
})
a //模拟异常
结果:
异常:ReferenceError: a is not defined
常见退出状态码
状态码 | 释义 |
---|---|
0 | 正常 |
1 | 有异常但未捕获 |
顶级变量指向
和filename
、dirname
不同,不同模块中的global
始终指向当前运行的模块
index.js:
var mk=require("./mk");
mk.say();
console.log(global.process.mainModule.filename); //C:\test\test.js
mk.js:
exports.say=function(){
console.log(global.process.mainModule.filename); //C:\test\test.js
}
常用工具
原型继承(inherits)
原型继承表示仅继承父对象的原型方法和函数,原生js
没有提供继承类
var util=require("util");
function person(name){
this.name=name;
this.say=function(){
console.log("Hello,my name is "+this.name);
}
}
person.prototype.show=function(){ //原型中添加一个方法
console.log("name="+this.name);
}
var p=new person("sam"); //person { name: 'sam', say: [Function] }
//原型方法和属性不会输出
console.log(p);
p.show(); //name=sam
//可以正常访问新增的方法
function student(){
this.showType=function(){
console.log("I'm student");
}
}
util.inherits(student,person);
/*util.inherits(constructor, superConstructor)
* student继承person
* 此方法仅能继承父的原型函数和方法;构造函数内的不会被继承
*/
var s=new student();
s.show(); //name=undefined
//构造函数内的属性未被继承
//s.say(); //构造函数内的方法未被继承
对象转字符串(inspect)
一般用于调试
var util=require("util");
var obj={
a: { b: { c: { d: { e: 'eee' } } } },
f:function(){}
}
console.log(obj); //{ a: { b: { c: [Object] } }, f: [Function: f] }
//默认递归2层
console.log(util.inspect(obj)); //{ a: { b: { c: [Object] } }, f: [Function: f] }
//默认递归2层
console.log(util.inspect(obj,true)); //显示详情
//{ a: { b: { c: [Object] } },f:
// { [Function: f]
// [length]: 0,
// [name]: 'f',
// [arguments]: null,
// [caller]: null,
// [prototype]: f { [constructor]: [Circular] } } }
console.log(util.inspect(obj,null,4)); //指定递归层数
//{ a: { b: { c: { d: { e: 'eee' } } } }, f: [Function: f] }
console.log(util.inspect(obj,null,null,true)); //以ANSI颜色编码,更好看
//色彩和console.log(obj)直出的效果一样
类型判断
数组类型判断(isArray)
var util=require("util");
console.log(typeof([])); //object
//原生的typeof分不出数组
console.log(util.isArray({})); //false
console.log(util.isArray([])); //true
console.log(util.isArray(new Array)); //true
正则表达式判断(isRegExp)
var util=require("util");
var emailReg=/\S*@\S*\.\S*/;
console.log(typeof(emailReg)); //Object
//原生的typeof分不出正则表达式
console.log(util.isRegExp(emailReg)); //true
console.log(util.isRegExp("/\S*@\S*\.\S*/")); //false
console.log(util.isRegExp(new RegExp("/\S*@\S*\.\S*/"))); //true
日期类型判断(isDate)
var util=require("util");
console.log(util.isDate({})); //false
console.log(util.isDate(new Date(1570971427052))); //true
异常判断(isError)
var util=require("util");
console.log(util.isError(new Error())); //true
console.log(util.isError(new TypeError())); //true
console.log(util.isError({name:"Error",message:"error at ..."})); //false
process.on("uncaughtException",function(code){
console.log(util.isError(code)); //true
})
a //模拟异常
文件系统
注:几乎所有方法都支持Sync
同步,虽然有的没有同步的示例
打开文件(open)
var fs=require("fs");
fs.open("a.txt","r+",function(err,fd){
if(err){
return console.log(err);
}
})
类型 | 描述 |
---|---|
r | 只读,不存在则报错 |
rs | 同步 |
r+ | 读写,不存在则报错 |
rs+ | 同步 |
w | 只写,不存在则创建 |
wx | 只写,若存在则不创建 |
w+ | 读写,不存在则创建 |
wx+ | 读写,若存在则不创建 |
a | 追加,不存在则创建 |
ax | 追加,若存在则不追加 |
a+ | 读写追加,不存在则创建 |
ax+ | 读写追加,若存在则不追加 |
获取文件信息(stat)
只能获取已打开的文件,接上面的open:
fs.stat("a.txt",function(err,stats){ //必须是已经open的文件
if(err){
return console.log(err);
}
console.log(stats.size);
console.log(stats.birthtimeMs);
console.log(stats.birthtime);
console.log(stats.atimeMs);
console.log(stats.atime);
console.log(stats.mtimeMs);
console.log(stats.mtime);
console.log(stats.ctimeMs);
console.log(stats.ctime);
console.log(stats.isFile());
console.log(stats.isDirectory());
console.log(stats.isBlockDevice());
console.log(stats.isCharacterDevice());
console.log(stats.isSymbolicLink());
console.log(stats.isFIFO());
console.log(stats.isSocket());
})
常用属性:
属性 | 描述 |
---|---|
size | 大小(字节) |
birthtimeMs | 创建日期时间戳 |
birthtime | 创建日期 |
atimeMs | 文件中数据库最后被访问的日期时间戳 |
atime | 文件中数据库最后被访问的日期 |
mtimeMs | 最后修改日期时间戳 |
mtime | 最后修改日期 |
ctimeMs | 最后元数据(权限,所有者…)修改日期时间戳 |
ctime | 最后元数据(权限,所有者…)修改日期 |
更多 | nlink ,uid ,gid ,rdev ,ino ,blocks ,blksize ,mode ,dev |
node.js
获取的时间时区不一样,差了8小时,可以手动补上:var sqpy=28800000; new Date(stats.birthtimeMs+sqpy);
常用方法:
方法 | 描述 |
---|---|
isFile | 是否为文件 |
isDirectory | 是否为目录 |
isBlockDevice | 是否为块设备 |
isCharacterDevice | 是否为字符设备 |
isSymbolicLink | 是否为软链接 |
isFIFO | 是否为FIFIO |
isSocket | 是否为Socket |
读写文件(writeFile,readFile,read)
格式
fs.writeFile(file, data[, options],callback)
fs.writeFileSync(file, data[, options])
fs.readFile(path[, options], callback)
fs.readFileSync(path[, options], callback)
options
参数:
参数 | 类型 | 描述 |
---|---|---|
encoding | String | 默认为utf8 |
mode (仅write 可用) | Integer | 默认为0o666 |
flag | String | 指定打开方式,write 默认为w ,read 默认为r |
读文件(readFile)
//异步
fs.readFile("a.txt",function(err,data){
if(err){
return console.log(err);
}
console.log(data.toString("UTF-8")); //Hello
})
//同步
var data=fs.readFileSync("a.txt");
console.log(data.toString("UTF-8")); //Hello
//options示例
console.log(fs.readFileSync("b.txt","UTF-8")); //指定编码
console.log(fs.readFileSync("b.txt",{encoding:"UTF-8",flag:"r"})); //指定所有参数
读文件(read)
fs.read(fd,buffer,offset,length,position,callback)
参数 | 描述 |
---|---|
fd | 描述符 |
buffer | 要写入(接收)的缓冲区 |
offset | 缓冲区起始写入偏移(起始写入位置) |
length | 被读文件的读取长度 |
position | 被读文件的起始读取位置 |
var buf=new Buffer.alloc(5); //用来存储读取的字符,长度为5字节
fs.open("a.txt","r",function(err,fd){
if(err){
return console.log(err);
}
//从buf的0开始存进5字节,从fd的第5开始读
fs.read(fd,buf,0,5,5,function(err,bytes,buffer){
if(err){
return console.error(err);
}
console.log("读取的字节数为:"+bytes); //5
console.log("buffer为:"+buffer.toString()); //world
console.log("读取的到内容为:"+buf.toString()); //world
})
});
写文件
//异步
fs.writeFile("a.txt","123",function(err){
if(err){
return console.log(err);
}
});
//同步
fs.writeFileSync("a.txt","456");
//options示例
fs.writeFile("b.txt","4aaa5888","UTF-8"); //指定编码
fs.writeFileSync("b.txt","4aaa5888",{encoding:"UTF-8",mode:0o666,flag:"wx"}); //更改打开方式为wx(b.txt若存在则不覆盖)
//open后再写
fs.open("a.txt","wx",function(err,fd){
if(err){
return console.log(err);
}
});
fs.writeFileSync("a.txt","aaa"); //这里虽然默认是w,但若有open就按open指定的方式(wx)
异步同步区别
- 异步读/写提供了一个回调函数,供读/写完成后处理文件
- 异步不必等待文件系统,其他代码不暂停
- 同步需要等待文件系统,浪费资源,效率低,不建议
关闭文件(close)
读写完之后,如果是在独占模式(例如r+
)下打开的文件,且未关闭文件,会导致其他程序无法读写该文件,所以需要及时关闭不用的文件
var buf=new Buffer.alloc(5);
fs.open("a.txt","r+",function(err,fd){ //以r+模式打开
if(err){
return console.log(err);
}
fs.read(fd,buf,0,5,5,function(err,bytes,buffer){
if(err){
return console.error(err);
}
/*fs.close(fd,function(err){ //若加上close则其他程序在该程序执行期间可正常读写
if(err){
console.log(err);
}
console.log("close ok");
});*/
})
});
process.on("beforeExit",function(code){ //模拟程序未执行完毕
setTimeout(function(){
console.log("保持运行...");
},1000);
})
截取文件(ftruncate,truncate)
ftruncate
:
var fs=require("fs");
fs.open("a.txt","r+",function(err,fd){
if(err){
return console.log(err);
}
console.log(fs.readFileSync(fd).toString()); //0123456789
fs.ftruncate(fd,5,function(err){ //取5个字符(0-4),其余部分删去
if(err){
return console.log(err);
}
console.log(fs.readFileSync("a.txt").toString()); //01234
})
});
truncate
:
fs.truncateSync("a.txt",5); //等同于上面,不用open就能截取
删除文件(unlink)
var fs=require("fs");
fs.unlink("a.txt",function(err){
if(err){
return console.error(err);
}
})
创建目录(mkdir)
var fs=require("fs");
//fs.mkdir(path[,options],callback)
//recursive:是否递归创建(若为假则不能创建例子中的文件夹),默认false,mode:权限,默认0777
fs.mkdir("test/123",{recursive:true,mode:0777},function(err){
if(err){
return console.error(err);
}
})
删除目录(rmdir)
rmdir
不支持递归删除,仅能读取一个
var fs=require("fs");
fs.rmdir("test/a",function(err){
if(err){
return console.error(err);
}
})
//fs.rmdir("test",function(){}); //会出错
递归删除目录(子文件):
var fs=require("fs");
function deleteFolderRecursive(path) {
if( fs.existsSync(path) ) {
fs.readdirSync(path).forEach(function(file) {
var curPath = path + "/" + file;
if(fs.statSync(curPath).isDirectory()) {
deleteFolderRecursive(curPath);
} else {
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(path);
}
};
deleteFolderRecursive("a");
读取目录(readdir)
readdir
不支持递归读取,仅能读取一层
目录树:
test
├───a
│ └───c
└───b
var fs=require("fs");
fs.readdir("test",function(err,files){
if(err){
return console.error(err);
}
files.forEach(function(file){ //a b
console.log(file);
})
})
递归读取目录:
var fs=require("fs");
function readdirR(dir){
fs.readdir(dir,function(err,files){
if(err){
return console.error(err);
}
files.forEach(function(file){ // test\a
// test\b
// test\a\c
console.log(dir+"\\"+file);
readdirR(dir+"\\"+file);
})
})
}
readdirR("test");
重命名(rename)
fs.renameSync("dir1","dir2"); //目录
fs.renameSync("a.txt","b.txt"); //文件