当你用 Node.js 处理大文件时,会不会遇到内存不足的问题?比如要读取几百兆的日志文件,或者处理上传的大视频,如果一次性把整个文件加载到内存里,很容易让服务器崩溃。
这时候,Node.js 的流(Streams)就派上用场了。
想象一下用水管接水。你不是等整个游泳池的水都准备好才用,而是打开水龙头,水就源源不断地流出来。Node.js 的流也是类似的道理。
流允许你一点一点地处理数据,而不是一次性把所有数据都读进内存。这对于处理大文件或者网络传输特别有用。
Node.js 主要有四种类型的流:
可读流:你可以从里面读取数据。比如从文件读取内容,或者接收网络请求。
可写流:你可以往里面写入数据。比如向文件写入内容,或者发送网络响应。
双工流:既可以读又可以写,就像电话通话,双方都能说和听。
转换流:在传输过程中修改数据。比如压缩文件,数据一边流过一边被压缩。
使用流有几个明显的好处:
节省内存:处理 1GB 的文件不需要 1GB 的内存,可能只需要几十KB
响应更快:不用等所有数据都准备好,收到一点处理一点
适合实时应用:聊天、视频直播都需要这种持续的数据流
假设你有一个几百兆的日志文件要分析,用传统方法会很慢:
const fs = require('fs');
// 不推荐的方法:一次性读取整个文件
fs.readFile('huge-logfile.txt', 'utf8', (err, data) => {
if (err) throw err;
// 等到文件全部读完后才执行这里
console.log('文件大小:', data.length);
});
如果文件很大,这种方法会占用大量内存,而且在读取完成前什么也做不了。
用流的方式就高效多了:
const fs = require('fs');
// 创建可读流
const readableStream = fs.createReadStream('huge-logfile.txt', {
encoding: 'utf8',
highWaterMark: 64 * 1024 // 每次读取 64KB
});
let totalSize = 0;
// 有数据到来时触发
readableStream.on('data', (chunk) => {
console.log(`收到 ${chunk.length} 字节数据`);
totalSize += chunk.length;
// 可以立即处理这一小块数据
processChunk(chunk);
});
// 数据读取完成
readableStream.on('end', () => {
console.log(`文件读取完成,总共 ${totalSize} 字节`);
});
// 错误处理
readableStream.on('error', (err) => {
console.error('读取文件出错:', err);
});
function processChunk(chunk) {
// 处理每一块数据
// 比如分析日志、提取信息等
}
这种方式就像小口吃饭,而不是一口吞下整个汉堡。
Node.js 提供了一个很实用的 pipe() 方法,让流之间的连接变得很简单。比如复制文件:
const fs = require('fs');
// 创建读取流和写入流
const readable = fs.createReadStream('source.txt');
const writable = fs.createWriteStream('copy.txt');
// 用管道连接它们:读取流 → 写入流
readable.pipe(writable);
// 监听完成事件
writable.on('finish', () => {
console.log('文件复制完成');
});
pipe() 会自动管理数据流动:当写入流忙的时候暂停读取,空闲的时候继续读取。
流在 Web 开发中特别有用。比如要提供视频播放服务:
const http = require('http');
const fs = require('fs');
http.createServer((req, res) => {
// 创建文件读取流
const videoStream = fs.createReadStream('big-video.mp4');
// 设置响应头
res.writeHead(200, {
'Content-Type': 'video/mp4',
'Content-Length': fs.statSync('big-video.mp4').size
});
// 将视频流管道连接到响应
videoStream.pipe(res);
}).listen(3000, () => {
console.log('服务器运行在 http://localhost:3000');
});
这样做的好处是:
内存占用很少,即使是几个GB的视频文件
用户可以边下载边观看,不用等整个文件下载完
支持多人同时观看不同视频
转换流可以在数据传输过程中进行修改。最常见的例子是压缩:
const fs = require('fs');
const zlib = require('zlib');
// 创建读取流
const readable = fs.createReadStream('large-file.txt');
// 创建写入流
const compressed = fs.createWriteStream('large-file.txt.gz');
// 读取 → 压缩 → 写入
readable.pipe(zlib.createGzip()).pipe(compressed);
compressed.on('finish', () => {
console.log('文件压缩完成');
});
数据流动的路径是:
从原始文件读取
经过 gzip 压缩
写入到压缩文件
整个过程就像流水线作业,每个环节只处理经过自己那一小部分数据。
使用流时一定要处理错误,否则出错时你都不知道发生了什么:
const fs = require('fs');
const readable = fs.createReadStream('input.txt');
const writable = fs.createWriteStream('output.txt');
// 处理读取错误
readable.on('error', (err) => {
console.error('读取失败:', err);
});
// 处理写入错误
writable.on('error', (err) => {
console.error('写入失败:', err);
});
// 使用管道
readable.pipe(writable);
writable.on('finish', () => {
console.log('操作成功完成');
});
Node.js 现在也支持用 async/await 来处理流,让代码更易读:
const { pipeline } = require('stream/promises');
const fs = require('fs');
const zlib = require('zlib');
async function compressFile() {
try {
await pipeline(
fs.createReadStream('input.txt'),
zlib.createGzip(),
fs.createWriteStream('input.txt.gz')
);
console.log('压缩成功');
} catch (err) {
console.error('压缩失败:', err);
}
}
compressFile();
在以下情况下考虑使用流:
处理大文件(视频、日志、数据库备份)
实时数据传输(聊天应用、视频会议)
需要边读取边处理的数据(文件格式转换、数据过滤)
网络通信(HTTP 请求/响应)
对于小文件或者简单的配置读取,用普通的 fs.readFile 和 fs.writeFile 更简单直接。
Node.js 的流是一个非常强大的功能,它让处理大文件和数据传输变得高效而优雅。通过分块处理数据,流可以:
大幅减少内存使用
提高应用性能
支持实时数据处理
掌握流的使用,是你从 Node.js 初学者进阶到中级开发者的重要一步。下次遇到大文件处理的需求时,不妨试试用流来解决,你会发现它的魅力所在。
本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!
关于 Node.js 里 ES6 Modules 的一次更新说明,总结来说:CommonJS 与 ES6 Modules 之间的关键不同在于代码什么时候知道一个模块的结构和使用它。
在这个教程中,我们会开发一个命令行应用,它可以接收一个 CSV 格式的用户信息文件,教程的内容大纲:“Hello,World”,处理命令行参数,运行时的用户输入,异步网络会话,美化控制台的输出,封装成 shell 命令,JavaScript 之外
首先你需要生成https证书,可以去付费的网站购买或者找一些免费的网站,可能会是key或者crt或者pem结尾的。不同格式之间可以通过OpenSSL转换
nodej项目在微信环境开发,nodejs的异步特效,会导致请求没有完成就执行下面的代码,出现错误。经过多方查找,可以使用async模块来异步转同步,只有前一个function执行callback,下一个才会执行。
3G的大文件分1500个2M二进度文件,通post方法发送给node服务,服务器全部接收到文件后,进组装生成你上文件。
JavaScript比C的开发门槛要低,尽管服务器端JavaScript存在已经很多年了,但是后端部分一直没有市场,JavaScript在浏览器中有广泛的事件驱动方面的应用,考虑到高性能、符合事件驱动、没有历史包袱这3个主要原因,JavaScript成为了Node的实现语言。
node.js的第一个基本论点是I / O的性能消耗是很昂贵。因此,使用当前编程技术的最大浪费来自于等待I / O完成。有几种方法可以处理性能影响
在前后端分离的开发中,通过 Restful API 进行数据交互时,如果没有对 API 进行保护,那么别人就可以很容易地获取并调用这些 API 进行操作。那么服务器端要如何进行鉴权呢?
我们经常跟Node.js打交道,即使你是一名前端开发人员 -- npm脚本,webpack配置,gulp任务,程序打包 或 运行测试等。即使你真的不需要深入理解这些任务,但有时候你会感到困惑,会因为缺少Node.js的一些核心概念而以非常奇怪的方式来编码。
运行在 Node.js 之上的 Webpack 是单线程模型的,也就是说 Webpack 需要处理的任务需要一件件挨着做,不能多个事情一起做。happypack把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!