Node.js基础(3)

Node.js的流

流可以看作是某段时间内从一个点移动到另一个点的数据序列。
Node.js中的流用于管理和处理数据,使用流完成对大量数据的操作以及逐段处理的操作。
流是Node.js中处理流式数据的抽象接口。
stream模块用于构建实现了流接口的对象
const stream = require(‘stream’);
stream模块主要用于开发人员创建新类型的流实例。

流的基本类型:

可写流(Writable)
可读流(Readable)
双工流(Duplex)
转换流(Transform)

流的实现类型

普通的流:基于字符串和Buffer(或Uint8Array)工作
对象模式的流:使用其他类型的JavaScript值工作

可写流和可读流都会在内部的缓冲器中存储数据,可缓冲的数据大小取决于传入流构造函数的highWaterMark选项(相当于水位线)。

双工流和转换流都是可读又可写的,各自维护着两个相互独立的内部缓冲器用于读取和写入。在维护数据流时,读取和写入两端可以各自独立地工作。

可读流

可读流是对提供数据的来源的一种抽象。所有可读流都实现了stream.Readable类定义的接口。
可读流有两种模式:流动(Flowing)和暂停(Paused)。

在这里插入图片描述
stream.Readable类定义的主要事件

  • data:当有数据可读时被触发。
  • end:没有更多的数据可读时被触发。
  • close:当流或其底层资源被关闭时被触发。

stream.Readable类定义的主要方法

  • readable.read([size]):从内部缓冲区拉取并返回数据。
  • readable.pause():使流动模式的流停止触发data事件,并切换出流动模式。
  • readable.setEncoding(encoding):为从可读流读取的数据设置字符编码。

可读流操作示例

可读流操作示例
const fs = require('fs')
//以流的方式读取文件
var readStream=fs.createReadStream('demo.txt');
var str='';//保存数据
readStream.on('data',function(chunk){
    str+=chunk;
})
//读取完成
readStream.on('end',function(chunk){
    console.log(str);
})
//读取失败
readStream.on('error',function(err){
    console.log(err);
})
可写流

可写流是对数据被写入的目的地的一种抽象。
所有可写流都实现了stream.Writable类定义的接口。
stream.Writable类定义的主要事件
close:当流或其底层资源被关闭时被触发。
error:写入数据发生错误时被触发。
finish:调用stream.end()方法且缓冲数据都已传给底层系统之后被触发。
stream.Writable类定义的主要方法
writable.write(chunk[, encoding][, callback]):写入数据到流,并在数据被完全处理之后调用回调函数。

可写流操作示例

const fs = require('fs')
var str = '这首歌真的很好听呢';
// 创建一个可以写入的流,写入到文件output.txt 中
var writerStream = fs.createWriteStream('output.txt');
// 使用 utf8 编码写入数据
writerStream.write(str,'UTF8');
// 标记文件末尾
writerStream.end();
// 处理流事件
writerStream.on('finish', function() {
    console.log('写入完成!');
});
writerStream.on('error', function(err){
    console.log('写入失败');
});
管道读写操作

管道操作将从一个流中获取的数据传递到另外一个流中。
可读流提供的readable.pipe()方法在可读流与可写流之间架起桥梁
readable.pipe(destination[, options])
将可读流的所有数据通过管道推送到文件的示例

const readable = getReadableStreamSomehow();//创建一个可读流
const writable = fs.createWriteStream('file.txt'); // 创建一个可写流
readable.pipe(writable); //管道读写操作,将readable 的所有数据都推送到文件file.txt

在单个可读流上绑定多个可写流,对流进行链式管道操作的示例

const fs = require('fs');
const r = fs.createReadStream('file.txt');
const z = zlib.createGzip();
const w = fs.createWriteStream('file.txt.gz');
r.pipe(z).pipe(w);// 链式管道操作两个可写流

默认当来源可读流触发end事件时,目标可写流也会调用stream.end()结束写入。
禁用默认行为,end选项设为false,目标流就会保持打开状态

reader.pipe(writer, { end: false });
reader.on('end', () => {
  writer.end('结束');
});

可读流发生错误,目标可写流不会自动关闭,需要手动关闭所有流以避免内存泄漏。
readable.unpipe()方法用于解绑之前使用stream.pipe()方法绑定的可写流。

提供图片浏览服务

搭建B/S架构

应用程序基于B/S架构,由Node.js内置的核心模块http提供Web服务。

const server = http.createServer(function(req, res){
     //请求处理并返回结果
});
server.listen(8000);
解析资源文件路径

获取请求的URL并返回文件路径名

var pathName = url.parse(req.url).pathname;

从文件路径名取得资源文件的绝对路径需要用到全局变量__dirname

var filePath = path.resolve(__dirname + pathName);

可以通过path.extname属性来获取文件的扩展名来确定文件类型

处理不同类型的资源文件

Content-Type的格式:
Content-Type:type/subtype ;parameter
由一个键值对集合来指定不同扩展名与Content-Type类型之间的对应关系

var mime = {
“.jpeg”: “image/jpeg”,
“.jpg”: “image/jpeg”,
}

文件读取

读取文件的状态

fs.stat(path,callback)

资源文件可以使用fs.createReadStream()方法打开。
静态文件服务器通常使用gzip压缩文件以提高传输效率,内置模块zlib提供gzip压缩功能。
可以在文件流发送到HTTP响应之前增加一个压缩文件的管道操作:

stream.pipe(zlib.createGzip()).pipe(res);

让浏览器知道已经开启gzip压缩,需要在HTTP消息头中提供相应的内容编码信息:

res.writeHead(200, { “content-encoding”: ‘gzip’ });

代码如下

//1
const http = require('http'); //加载http模块
const path = require('path');
const fs = require('fs')
const url = require('url')
var curDir = ''; //当前目录名
//创建HTTP服务
const server = http.createServer(function (req, res) {
//定义mime对象设置相应的响应头类型,这里仅列出少量的扩展名用于测试
var mime = {
    ".jpeg": "image/jpeg",
    ".jpg": "image/jpeg",
    ".png": "image/png",
    ".tiff": "image/tiff",
    ".pdf": "application/pdf"
};
//获取请求URL并转换请求路径
var pathName = url.parse(req.url).pathname;
//获取请求URL并转换请求路径
//2
//对路径进行解码以防中文乱码
var pathName = decodeURI(pathName);
//获取资源文件的绝对路径,这里用到全局变量__dirname
var filePath = path.resolve(__dirname + pathName);
console.log(filePath); //控制台显示绝对路径
//获取文件的扩展名
var extName = path.extname(pathName);
//为简化处理,没有扩展名的或未知类型使用text/plain表示
var contentType = mime[extName] || "text/plain";
//3
//通过读取文件状态来决定如何读取静态文件
fs.stat(filePath, function (err, stats) {
    if(err){
        res.writeHead(404,{'content-type':'text/html'})
        res.end("<h1>404 没有找到</h1>")
    }
    //文件存在且没有错误
    if(!err && stats.isFile()){
        readFile(filePath,contentType);
    }
    //如果路径是目录
    if (!err && stats.isDirectory()) {
        var html = "<head><meta charset = 'utf-8'/></head><body><ul>";
        curDir = path.basename(path.relative(__dirname, filePath)); //获取当前目录
        fs.readdir (filePath,(err,files) =>{
            if(err){
                console.log('读取路径失败');
            }else{
                for (var file of files) {
                    //这里用到了ES6模板字符串
                    var curPath = path.join(curDir, file);
                    html += `<li><a href='${filecurPath}'>${file}</a></li>`;
                }
                html += '</ul></body>'; 
                res.writeHead(200, {
                    'content-type': "text/html"
                });
                res.end(html);
            }
        });
       
       
    }

//4
//声明函数流式读取文件
function readFile(filePath, contentType) {
//设置HTTP消息头
res.writeHead(200, {
    'content-type': contentType,
    'content-encoding': 'gzip'
});
//创建流对象读取文件
var stream = fs.createReadStream(filePath);
//流式读取错误处理
stream.on('error', function () {
    res.writeHead(500, {
        'content-type': contentType
    });
    res.end("<h1>500 服务器错误</h1>");
});
//链式管道操作将文件内容流到客户端
stream.pipe(zlib.createGzip()).pipe(res);
}
});
});
//5
var port = 8000; //指定服务器监听的接口
server.listen(port, function () {
    console.log(`图片服务器正运行在端口:${port}`);
    console.log(`访问网址: http://localhost:${port}`);
});
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值