本文学习Node.js的四个基本模块:fs
、stream
、http
、crypto
。
学习链接:
https://www.liaoxuefeng.com/wiki/1022910821149312/1023025763380448
https://www.nodebeginner.org/index-zh-cn.html
一、fs(读文件、写文件、stat)
- Node.js 内置的
fs
模块就是文件系统模块,负责读写文件。fs
模块同时提供了同步和异步的方法。
异步读文件
按照JavaScript标准,异步读取一个文本文件代码如下:
'use strict' var fs = require('fs'); fs.readFile(`sample.txt`,`utf-8`,function(err,data){ if(err){ console.log(err) } else{ console.log(data) } })
如果我们要读取的文件不是文本文件,而是二进制文件,下面的例子演示了读取一个图片文件:
'use strict' var fs = require('fs'); fs.readFile(`sample.png`,function(err,data){ if(err){ console.log(err) } else{ console.log(data) console.log(data.length + `bytes`) } })
当读取二进制文件时,不传入文件编码时,回调函数的data参数将返回一个Buffer对象。在Node.js中,Buffer对象就是一个包含零个或任意个字节的数组(注意和Array不同)。
Buffer对象可以和String对象做转换:
//Buffer => String var str = data.toString('utf-8') //String=> Buffer var buf= Buffer.from(str,'utf-8')
同步读文件
除了标准的异步读取模式外,fs也提供相应的同步读取函数。同步读取的函数和异步函数相比,多了一个Sync后缀,并且不接收回调函数,函数直接返回结果。
用fs模块同步读取一个文本文件的代码如下:
'use strict'; var fs = require('fs'); var data = fs.readFileSync('sample.txt', 'utf-8'); console.log(data);
写文件
将数据写入文件是通过
fs.writeFile()
实现的。'use strict'; var fs = require('fs'); var data = 'Hello, Node.js'; fs.writeFile('output.txt', data, function (err) { if (err) { console.log(err); } else { console.log('ok.'); } });
writeFile()的参数依次为文件名、数据和回调函数。如果传入的数据是String,默认按UTF-8编码写入文本文件,如果传入的参数是Buffer,则写入的是二进制文件。回调函数由于只关心成功与否,因此只需要一个err参数。
和readFile()类似,writeFile()也有一个同步方法,叫writeFileSync()
'use strict'; var fs = require('fs'); var data = 'Hello, Node.js'; fs.writeFileSync('output.txt', data);
stat
如果我们要获取文件大小,创建时间等消息,可以使用
fs.stat()
,它返回一个Stat对象,能告诉我们文件或目录的详细信息。'use strict'; var fs = require('fs'); fs.stat('sample.txt', function (err, stat) { if (err) { console.log(err); } else { // 是否是文件: console.log('isFile: ' + stat.isFile()); // 是否是目录: console.log('isDirectory: ' + stat.isDirectory()); if (stat.isFile()) { // 文件大小: console.log('size: ' + stat.size); // 创建时间, Date对象: console.log('birth time: ' + stat.birthtime); // 修改时间, Date对象: console.log('modified time: ' + stat.mtime); } } });
运行结果如下:
isFile: true
isDirectory: false
size: 181
birth time: Fri Dec 11 2015 09:43:41 GMT+0800 (CST)
modified time: Fri Dec 11 2015 12:09:00 GMT+0800 (CST)
stat()
也有一个对应的同步函数statSync()
二、Stream
Stream是Node.js提供的又一个在服务区端可用的模块, 目的是支持“流”这种数据结构。
在Node.js中,流也是一个对象,我们只需要响应流的事件:data
事件表示流的数据已经可以读取了,end
事件表示这个流已经到末尾了 ,没有数据可以读取了,error
事件表示出错了。
下面是一个从文件流读取文本内容的示例:`use strict` var fs = require('fs'); //打开一个流 var rs = fs.createReadStream(`sample.txt`,`utf-8`) rs.on('data',function(chrunk){ console.log('DATA:') console.log(chunk); }) rs.on('end', function () { console.log('END'); }); rs.on('error', function (err) { console.log('ERROR: ' + err); });
要注意,
data
事件可能会有多次,每次传递的chunk
是流的一部分数据。
要以流的形式写入文件,只需要不断调用write()
方法,最后以end
结束:'use strict'; var fs = require('fs'); var ws1 = fs.createWriteStream('output1.txt', 'utf-8'); ws1.write('使用Stream写入文本数据...\n'); ws1.write('END.'); ws1.end(); var ws2 = fs.createWriteStream('output2.txt'); ws2.write(new Buffer('使用Stream写入二进制数据...\n', 'utf-8')); ws2.write(new Buffer('END.', 'utf-8')); ws2.end();
所有可以读取数据的流都继承自
stream.Readable
,所有可以写入的流都继承自stream.Writable
。pipe
两个流可以串起来,一个
Readable
流和一个Writable
流串起来后,所有的数据自动从Readable
流进入Writable
流,这种操作叫pipe
。'use strict'; var fs = require('fs'); var rs = fs.createReadStream('sample.txt'); var ws = fs.createWriteStream('copied.txt'); rs.pipe(ws);
三、http
从服务器模块开始,在项目的根目录下创建一个叫server.js的文件,并写入以下代码,对如下代码进行一个清晰的学习:
var request = require('http') http.createServer(function(request,response){ response.writeHead(200,{"Content-type":"text/plain"}) response.write("hello world") response.end() }).listen(8888)
然后我们现在开始分析HTTP服务器的构成:
- 首先,因为Node.js自带http模块,所以通过require引用该模块。
- 接下来调用http模块提供的函数:
createServer
,这个函数会返回一个对象,这个对象有一个叫做listen的方法,这个方法有一个数值参数,指定这个HTTP服务器监听的端口号。- 我们继续查看上面的代码,发现createServer这个函数运用了函数传递的方式来让HTTP服务器工作。
- 接着我们将上面的代码进行改写:
var request = require('http') function onRequest(request,response){ response.writeHead(200,{"Content-type":"text/plain"}) response.write("hello world") response.end() }) http.createServer(onRequest).listen(8888)
接着思考:为什么要用上面的那种方式?
简单回答说:这是基于事件驱动的回调。即:Node.js原生的工作方式(事件驱动)
四、crypto
crypto模块的目的是为了提供通用的加密和哈希算法。用纯JavaScript代码实现这些功能不是不可能,但速度会非常慢。Nodejs用C/C++实现这些算法后,通过cypto这个模块暴露为JavaScript接口,这样用起来方便,运行速度也快。
Md5和SHA1
MD5是一种常用的哈希算法,用于给任意数据一个签名,这个签名通常用一个十六进制的字符串表示:
const crypto = require('crypto') const hash = crypto.createHash('md5'); hash.update('hello') console.log(hash.digest('hex'));//5d41402abc4b2a76b9719d911017c592
如果要计算SHA1,只需要把'md5'改成'SHA1',就可以得到SHA1的结果,还可以使用更安全的
sha256
和sha512
Hmac
Hmac算法也是一种哈希算法,它可以利用MD5或SHA1等哈希算法,不同的是Hmac还需要一个秘钥:
const crypto = require('crypto') const hmac = crypto.createHmac('sha256','secret-key'); hmac.update('Hello, nodejs!'); console.log(hmac.digest('hex')); // 21d8ff89e..
只要密钥发生了变化,那么同样的输入数据也会得到不同的签名,因此,可以把Hmac理解为用随机数“增强”的哈希算法。
AES
AES是一种常用的对称加密算法,加解密都用同一个密钥。crypto模块提供了AES支持,但是需要自己封装好函数,便于使用:
const crypto = require('crypto'); function aesEncrypt(data, key) { const cipher = crypto.createCipher('aes192', key); var crypted = cipher.update(data, 'utf8', 'hex'); crypted += cipher.final('hex'); return crypted; } function aesDecrypt(encrypted, key) { const decipher = crypto.createDecipher('aes192', key); var decrypted = decipher.update(encrypted, 'hex', 'utf8'); decrypted += decipher.final('utf8'); return decrypted; } var data = 'Hello, this is a secret message!'; var key = 'Password!'; var encrypted = aesEncrypt(data, key); var decrypted = aesDecrypt(encrypted, key); console.log('Plain text: ' + data); console.log('Encrypted text: ' + encrypted); console.log('Decrypted text: ' + decrypted);
运行结果如下:
Plain text: Hello, this is a secret message!
Encrypted text: 8a944d97bdabc157a5b7a40cb180e7...
Decrypted text: Hello, this is a secret message!可以看出,加密后的字符串通过解密又得到了原始内容。
注意到AES有很多不同的算法,如aes192,aes-128-ecb,aes-256-cbc等,AES除了密钥外还可以指定IV(Initial Vector),不同的系统只要IV不同,用相同的密钥加密相同的数据得到的加密结果也是不同的。加密结果通常有两种表示方法:hex和base64,这些功能Nodejs全部都支持,但是在应用中要注意,如果加解密双方一方用Nodejs,另一方用Java、PHP等其它语言,需要仔细测试。如果无法正确解密,要确认双方是否遵循同样的AES算法,字符串密钥和IV是否相同,加密后的数据是否统一为hex或base64格式。
…………
转载于:https://www.jianshu.com/p/1857728f72d3