这两天在工作之余学习
Node.js
,整理了其中一些基础api
,并写了一些基础的demo
下面是自己对于
path
、buffer
、event
、fs
这几个常用到api
的一些用法整理。
一,PATH
模块提供了一些工具函数,用于处理文件与目录的路径。
1,path.normalize(path)
path.normalize()
方法会规范化给定的 path
,并解析 '..'
和 '.'
片段
例子
const { normalize } = require('path');
console.log(normalize('/user//local/bin'));
console.log(normalize('/user//local/../bin'));
结果如图
2,path.join([...paths])
path.join()
方法使用平台特定的分隔符把全部给定的 path
片段连接到一起,并规范化生成的路径。
例子
const { normalize,join } = require('path');
console.log(join('/foo', 'bar', 'baz/asdf', 'quux', '..'));
console.log(join('/usr','../local','bin/'));
结果如图
3,path.resolve([...paths])
path.resolve()
方法会把一个路径或路径片段的序列解析为一个绝对路径。
例子
const { resolve } = require('path');
console.log(resolve('./'));
console.log(resolve('/foo/bar', './baz'));
console.log(resolve('/foo/bar', '/tmp/file/'));
结果如图
4,basename
:文件名;extname
:文件的拓展名;dirnam
:目录名文件所在的路径
例子
const { dirname,extname,basename } = require('path');
const filePath = '/usr/local/bin/no.txt';
console.log(dirname(filePath)); // '/usr/local/bin'
console.log(extname(filePath)); // '.txt'
console.log(basename(filePath)); // 'no.txt'
结果如图
5,path.parse
,path.format
path.parse()
方法返回一个对象,对象的属性表示 path
的元素。返回的对象有以下属性:root
、dir
、base
、ext
、name
;
path.format()
方法会从一个对象返回一个路径字符串。 与 path.parse()
相反。
例子
const { parse,format } = require('path');
const filePath = '/usr/local/bin/node_module/package.json';
const ret = parse(filePath);
console.log(ret)
console.log(format(ret));
结果如图
需要注意的点
当 pathObject
提供的属性有组合时,有些属性的优先级比其他的高:
- 如果提供了
pathObject.dir
,则pathObject.root
会被忽略 - 如果提供了
pathObject.base
存在,则pathObject.ext
和pathObject.name
会被忽略
//1, 如果提供了 `dir`、`root` 和 `base`,则返回 `${dir}${path.sep}${base}`。
// `root` 会被忽略。
path.format({
root: '/ignored',
dir: '/home/user/dir',
base: 'file.txt'
});
// 返回: '/home/user/dir/file.txt'
// 2,如果没有指定 `dir`,则 `root` 会被使用。
// 如果只提供了 `root` 或 `dir` 等于 `root`,则平台的分隔符不会被包含。
// `ext` 会被忽略。
path.format({
root: '/',
base: 'file.txt',
ext: 'ignored'
});
// 返回: '/file.txt'
// 3,如果没有指定 `base`,则 `name` + `ext` 会被使用。
path.format({
root: '/',
name: 'file',
ext: '.txt'
});
// 返回: '/file.txt'
6,sep
,delimiter
,win32
,posix
delimiter
提供平台特定的路径分隔符:
- Windows 上是
;
- POSIX 上是
:
sep
提供了平台特定的路径片段分隔符:
- Windows 上是
\
- POSIX 上是
/
path.win32
属性提供了 path
方法针对 Windows 的实现;
path.posix
属性提供了 path
方法针对 POSIX 的实现。
例子
// mac下
const { sep,delimiter,win32,posix } = require('path');
console.log('PATH:',process.env.PATH); // "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
console.log('sep:',sep); // "/"
console.log('win sep:',win.sep); // "\"
console.log('delimiter:',delimiter); // ":"
console.log('delimiter:',win.delimiter); // ";"
结果如图
7,关于路径的注意点
__dirname
,process.cwd()
,path.resolve()
三者的区别
例子
//1,在项目的根目录执行:
$ ~/Desktop/node_demo $ node index.js
============代码============
const path = require('path');
const mod = require('./test.js');
console.log(mod.testVar); // 5
console.log('__dirname',__dirname); // "/Users/fujiawei/Desktop/node_demo"
console.log('process.cwd()',process.cwd()); // "/Users/fujiawei/Desktop/node_demo"
console.log('./',path.resolve('./')); // "/Users/fujiawei/Desktop/node_demo"
===================
//2,在Desktop执行
$ ~/Desktop $ node node_demo/index.js
============代码============
const path = require('path');
const mod = require('./test.js');
console.log(mod.testVar); // 5
console.log('__dirname',__dirname); // "/Users/fujiawei/Desktop/node_demo"
console.log('process.cwd()',process.cwd()); // "/Users/fujiawei/Desktop"
console.log('./',path.resolve('./')); // "/Users/fujiawei/Desktop"
-
__dirname
与__filename
总是返回文件的绝对路径,即物理磁盘上的路径 -
process.cwd()
总是返回执行node
命令时所在的文件夹路径,当前在哪里启动的脚本路径 -
./
在require
方法中总是相对当前文件所在文件夹的路径;在其他的地方和process.cwd()
一样,相对node
启动文件夹
二,buffer
Buffer
处理二进制数据流;实例类似整数数组;大小固定;C++
代码在V8
堆外分配物理内存
1,Buffer.alloc()
-
size
新建的Buffer
期望的长度 -
fill
用来预填充新建的Buffer
的值。 默认:0
-
encoding
如果fill
是字符串,则该值是它的字符编码。 默认:'utf8'
分配一个大小为 size
字节的新建的 Buffer
。 如果 fill
为 undefined
,则该 Buffer
会用 0 填充。
例子
var buf1 = Buffer.alloc(10);
console.log(buf1);
结果如图
例子
var buf1 = Buffer.alloc(10,1);
console.log(buf1);
结果如图
2,Buffer.allocUnsafe()
分配一个大小为 size
字节的新建的 Buffer
。 如果 size
大于 buffer.constants.MAX_LENGTH
或小于 0,则抛出 RangeError
错误。 如果 size
为 0,则创建一个长度为 0 的 Buffer
。
以这种方式创建的 Buffer
实例的底层内存是未初始化的。 新创建的 Buffer
的内容是未知的,且可能包含敏感数据。 可以使用 buf.fill(0)
初始化 Buffer
实例为0。
例子
var buf1 = Buffer.allocUnsafe(10);
console.log(buf1);
结果如图
3,Buffer.from()
array
通过一个八位字节的 array
创建一个新的 Buffer
。
例子
var buf1 = Buffer.from([1,2,3]);
console.log(buf1);
结果如图
例子
var buf1 = Buffer.from('text'); // 默认utf8
console.log(buf1);
结果如图
var buf1 = Buffer.from('text', 'base64')
console.log(buf1);
4,Buffer.byteLength()
-
string
要计算长度的值 -
encoding
如果string
是字符串,则这是它的字符编码。 默认:'utf8'
- 返回:
string
包含的字节数
返回一个字符串的实际字节长度。 这与 String.prototype.length
不同,因为那返回字符串的字符数。
例子
var buf1 = Buffer.byteLength('text')
console.log(buf1); // 4
var buf2 = Buffer.byteLength('测试')
console.log(buf2); // 6
5,Buffer.isBuffer()
如果 obj
是一个 Buffer
则返回 true
,否则返回 false
。
var buf1 = Buffer.isBuffer({})
console.log(buf1); // false
var buf2 = Buffer.isBuffer(Buffer.from([1,2,3]))
console.log(buf2); // true
6,Buffer.concat()
-
list
要合并的Buffer
或Uint8Array
实例的数组 -
totalLength
合并时list
中Buffer
实例的总长度 - 返回:
buffer
返回一个合并了 list
中所有 Buffer
实例的新建的 Buffer
。
例子
const buf1 = Buffer.from('this ');
const buf2 = Buffer.from('is ');
const buf3 = Buffer.from('good!');
var buf = Buffer.concat([buf1,buf2,buf3])
console.log(buf.toString());
结果如图
接下来是buffer
的实例方法:
7,buf.length
返回 buf
在字节数上分配的内存量。 注意,这并不一定反映 buf
内可用的数据量。
例子
var buf = Buffer.from('good!')
console.log(buf.length); // 5
8,buf.toString()
将buffer
转化为字符串
例子
var buf = Buffer.from('good!')
console.log(buf.toString()); // good!
console.log(buf.toString('base64')); // Z29vZCE=
9,buf.fill()
填充buffer
。
-
value
用来填充buf
的值。 -
offset
开始填充buf
前要跳过的字节数。默认:0
。 -
end
结束填充buf
的位置(不包含)。默认:buf.length
。 -
encoding
如果value
是一个字符串,则这是它的字符编码。默认:'utf8'
。 - 返回:
buf
的引用。
如果未指定 offset
和 end
,则填充整个 buf
。 这个简化使得一个 Buffer
的创建与填充可以在一行内完成。
例子
var buf1 = Buffer.allocUnsafe(10);
console.log(buf1)
console.log(buf1.fill(10,2,6)); // good!
结果如图
10,buf.equals()
如果 buf
与 otherBuffer
具有完全相同的字节,则返回 true
,否则返回 false
。
例子
var buf4 = Buffer.from('test');
var buf5 = Buffer.from('test');
var buf6 = Buffer.from('test!');
console.log(buf4.equals(buf5)); // true
console.log(buf4.equals(buf6)); // false
11,buf.indexOf()
如javascript
的indexOf
的方法。
例子
var buf4 = Buffer.from('test');
console.log(buf4.indexOf('es')); // 1
console.log(buf4.indexOf('a')); // -1
12,buffer
打印例子
一个文字的字符是3,所以会出现乱码。
例子
const buf = Buffer.from('中文字符串!');
for (let i = 0;i < buf.length; i += 5) {
const b = Buffer.allocUnsafe(5);
buf.copy(b, 0, i);
console.log(b.toString());
}
const StringDecoder = require('string_decoder').StringDecoder;
const decoder = new StringDecoder('utf8');
for (let i = 0;i < buf.length; i += 5) {
const b = Buffer.allocUnsafe(5);
buf.copy(b, 0, i);
console.log(decoder.write(b));
}
结果如图
三,event
,事件机制
事件驱动和异步i/o
,大多数 Node.js 核心 API 都采用惯用的异步事件驱动架构,其中某些类型的对象(触发器)会周期性地触发命名事件来调用函数对象(监听器)。
所有能触发事件的对象都是 EventEmitter
类的实例。 这些对象开放了一个 eventEmitter.on()
函数,允许将一个或多个函数绑定到会被对象触发的命名事件上。 事件名称通常是驼峰式的字符串,但也可以使用任何有效的 JavaScript 属性名。
当 EventEmitter
对象触发一个事件时,所有绑定在该事件上的函数都被同步地调用。 监听器的返回值会被丢弃。
1,最简单的demo
例子
const EventEmitter = require('events');
class CustomEvent extends EventEmitter {}
const ce = new CustomEvent();
ce.on('test', ()=> {
console.log('this is test');
})
setInterval(()=>{
ce.emit('test');
},500);
结果如图
2,定制抛出错误的事件处理程序
例子
const EventEmitter = require('events');
class CustomEvent extends EventEmitter {}
const ce = new CustomEvent();
ce.on('error', (err,time) => {
console.log(err);
console.log(time);
})
ce.emit('error',new Error('失败了'), Date.now()); // 第二个是穿给时间的参数
结果如图
3,只响应一次事件
例子
const EventEmitter = require('events');
class CustomEvent extends EventEmitter {}
const ce = new CustomEvent();
ce.once('test', () => {
console.log('test event');
})
setInterval(()=>{
ce.emit('test');
},500);
结果如图
4,删除事件
分为删除事件的具体的某一个方法:ce.removeListener(事件名,具体方法)
例子
const EventEmitter = require('events');
class CustomEvent extends EventEmitter {}
const ce = new CustomEvent();
function fn1 () {
console.log('fn1');
}
function fn2 () {
console.log('fn2');
}
ce.on('test',fn1);
ce.on('test',fn2);
setInterval(()=>{
ce.emit('test');
},500);
setInterval(()=>{
// 移除某一个方法
ce.removeListener('test',fn1); // 删除test事件的fn1函数
},1500);
结果如图
删除事件所有方法,即删除事件:ce.removeAllListeners(事件名)
例子
const EventEmitter = require('events');
class CustomEvent extends EventEmitter {}
const ce = new CustomEvent();
function fn1 () {
console.log('fn1');
}
function fn2 () {
console.log('fn2');
}
ce.on('test',fn1);
ce.on('test',fn2);
setInterval(()=>{
ce.emit('test');
},500);
setInterval(()=>{
// 移除所有的事件
ce.removeAllListeners('test');
},1500);
结果如图
四,fs
:文件系统
文件 I/O 是对标准 POSIX 函数的简单封装。 通过 require('fs')
使用该模块。 所有的方法都有异步和同步的形式。
异步方法的最后一个参数都是一个回调函数。 传给回调函数的参数取决于具体方法,但回调函数的第一个参数都会保留给异常。 如果操作成功完成,则第一个参数会是 null
或 undefined
。
1,fs.readFile
:读文件
例子
fs.readFile('./index.js',(err,data) => {
if(err) throw err;
console.log(data);
});
结果如图
buffer
变成string
fs.readFile('./index.js','utf8', (err,data) => {
if(err) throw err;
console.log(data);
});
结果如图
报错:找不到相应的文件夹的时候
例子
fs.readFile('./index.jss','utf8', (err,data) => {
if(err) throw err;
console.log(data);
});
结果如图
同步读文件
const data = fs.readFileSync('./test.js','utf8');
console.log(data);
结果如图
2,写文件:fs.writeFile
例子
fs.writeFile('./test1.js','this is test','utf8',(err) => {
if(err) throw err;
console.log('done');
});
结果如图
将buffer
写入到文件中去
const content = Buffer.from('this is test');
fs.writeFile('./test1.js', content, (err) => {
if(err) throw err;
console.log('done');
});
结果如图
3,文件信息:fs.stat
返回的stats
有判断是否为文件和是否为文件夹的方法;
fs.stat('./index.js',(err, stats) => {
if(err) throw err;
console.log("是否为文件:",stats.isFile()); // 是否为文件
console.log("是否为文件夹:",stats.isDirectory()); // 是否为文件夹
console.log("stats详细信息:",stats);
});
结果如图
查找文件是否存在
fs.stat('./index.jsf',(err, stats) => {
if(err) {
console.log('文件不存在');
return;
};
console.log(stats.isFile()); // 是否为文件
console.log(stats.isDirectory()); // 是否为文件夹
console.log(stats);
});
结果如图
4,重命名:fs.rename
:参数是要改名字的文件,需要修改成的名字,以及回调函数。
例子
fs.rename('./test1.js','test.txt', (err) => {
if(err) {
if(err) throw err;
};
console.log('done');
});
5,删除fs.unlink
例子
fs.unlink('./test.txt', (err) => {
if(err) throw err;
console.log('done');
});
6,查找文件夹fs.readdir
fs.readdir('./', (err,files) => {
if(err) throw err;
console.log(files);
});
结果如图
7,创建文件夹fs.mkdir
fs.mkdir('aaaa', (err) => {
if(err) throw err;
});
8,删除文件夹fs.rmdir
fs.rmdir('aaaa', (err) => {
if(err) throw err;
});
9,监视文件的变化fs.watch
,会监视每一次文件的变化,以及变化的文件名。
fs.watch('./', {
recursive:true //是否递归
}, (eventType, filename) => { // 变化类型与变化文件名
console.log(eventType, filename);
});
结果如图
10,比较复杂的,stream
是流的意思,方向与数据是条件,用到的场景看电影等
fs.createReadStream
读流,pipe
控制流的方向,fs.createWriteStream
是创建一个流,并可以向里面写数据,这里模拟异步的方式,当随机数小于7的时候我们就往text.txt
中写数据。
例子
// 创建一个stream。
const rs = fs.createReadStream('./test.js');
rs.pipe(process.stdout);// 控制方向
// 开始写stream,创建一个stream。
const ws = fs.createWriteStream('./text.txt');
const tid = setInterval(() => {
const num = parseInt(Math.random() * 10 );
console.log(num);
if(num < 7) {
ws.write(num + '');
} else {
clearInterval(tid);
ws.end();
}
}, 200);
ws.on('finish',() => {
console.log('done');
})
结果如图
写入到text.txt
的值
11,解决回调地狱,我们使用promise
与async await
解决
例子
const promiseify = require('util').promisify;
var read = promiseify(fs.readFile);
read('./fs.js').then(data => {
console.log(data.toString());
}).catch(ex => {
console.log(ex)
})
结果如图
async await
: async function
在 node
> 8.0 就可以使用。
const promiseify = require('util').promisify;
var read = promiseify(fs.readFile);
//
async function test() {
try{
const content = await read('./fs.js');
console.log(content.toString());
} catch (ex) {
console.log(ex)
}
}
test()
结果如图
五,参考文件
此篇文章是参考了Node.js
中文网,自己写的一些api
小demo
希望这篇文章对大家能有帮助,来自一个奔跑在前端路上的前端小白。