加载中

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服务器下载别人或上传自己的第三方包和命令行程序
NPMNode.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:交互式解释器),类似windowscmdlinuxshell,提供交互功能

执行语句

表达式运算

>(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
  1. 可以创建多个名称相同的监听器,这些监听器按书写顺序依次执行
  2. 触发某个名称的监听器时,所有该名称的监听器都会被触发,即使参数个数不对应,没有的参数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中的windowNode.js也有顶级变量global

顶级变量事件

事件意义
eixt程序结束时触发
beforeExit程序结束前触发
uncaughtException捕获异常

eixtbeforeExit

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有异常但未捕获

顶级变量指向

filenamedirname不同,不同模块中的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参数:

参数类型描述
encodingString默认为utf8
mode(仅write可用)Integer默认为0o666
flagString指定打开方式,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)

异步同步区别

  1. 异步读/写提供了一个回调函数,供读/写完成后处理文件
  2. 异步不必等待文件系统,其他代码不暂停
  3. 同步需要等待文件系统,浪费资源,效率低,不建议

关闭文件(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");  //文件
posted @ 2019-11-09 14:13  jialeYang  阅读(114)  评论(0编辑  收藏  举报