Node.js的基本模块(fs、stream、http、crypto)

本文学习Node.js的四个基本模块:fsstreamhttpcrypto
学习链接:
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的结果,还可以使用更安全的sha256sha512

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

猜你喜欢

转载自blog.csdn.net/weixin_34244102/article/details/91080537