
文件流
发布日期:2021-05-07 23:09:05
浏览次数:30
分类:精选文章
本文共 3781 字,大约阅读时间需要 12 分钟。
什么是文件流?
文件流(File Stream)是数据在计算机系统中从一个位置流动到另一个位置的过程。它类似于数据管道,允许程序在不将整个文件读入内存的情况下,逐块处理文件内容。
文件流的类型
可读流(Readable)
可读流用于从外部设备(如磁盘、网卡、显卡等)读取数据到内存。例如,磁盘上的文件通过可读流被读取到内存中供处理。可写流(Writeable)
可写流用于将内存中的数据写入外部设备。例如,程序将内存中的数据通过可写流写入磁盘或其他外部存储设备。双工流(Duple)
双工流允许数据在同一时间从外部设备流入内存,同时从内存流出到外部设备。这种机制在处理大文件时特别有用。为什么需要文件流?(节省内存)
文件流的主要优势是节省内存,特别是在处理外部设备(如磁盘)与内存规模不一致的情况下。
1. 外部设备与内存规模不一致
- 内存小,外部设备大:例如,内存只有1GB,但磁盘有2GB的数据。由于一次无法读完整个文件,需要通过文件流逐块读取和处理。
2. 外部设备与内存处理速度不匹配
- 内存处理速度快,外部设备速度慢:例如,内存将1GB数据写入磁盘可能需要5秒,期间其他操作会受到影响。文件流允许磁盘在后台处理数据,而不会阻塞其他任务。
3. 大文件读写效率低
- 内存数据过多导致执行时间变长。文件流可以避免一次性读入或写出大文件,从而提高处理效率。
文件可读流
文件可读流(ReadStream)允许程序逐块读取文件内容,而不需要一次性加载整个文件到内存。
创建可读流
const fs = require("fs");const path = require("path");const filename = path.resolve(__dirname, "./1.txt");const rs = fs.createReadStream(filename, { encoding: "utf-8", highWaterMark: 1, // 根据编码格式决定一次读取多少字符 autoClose: true, // 读取完成后自动关闭文件});
可读流事件监听
open
:文件打开时触发。error
:读取过程中发生错误。close
:文件读取完成。end
:文件读取完成,所有数据都已处理。data
:接收到文件块时触发。pause
:读取暂停时触发。resume
:读取恢复时触发。
示例代码
const fs = require("fs");const path = require("path");const filename = path.resolve(__dirname, "./1.txt");const rs = fs.createReadStream(filename, { encoding: "utf-8", highWaterMark: 1, autoClose: true,});rs.on("open", () => { console.log("打开文件");});rs.on("error", (err) => { console.log("出错了!!!");});rs.on("close", () => { console.log("文件关闭");});rs.on("end", () => { console.log("文件读完了");});rs.on("data", (data) => { console.log(data); rs.pause(); // 暂停读取});rs.on("pause", () => { console.log("暂停了"); setTimeout(() => { rs.resume(); // 恢复读取 }, 1000);});rs.on("resume", () => { console.log("恢复了");});
文件可写流
文件可写流(WriteStream)允许程序逐块向外部设备(如磁盘)写入数据,而不需要一次性加载整个文件到内存。
创建可写流
const fs = require("fs");const path = require("path");const filename = path.resolve(__dirname, "./3.txt");const ws = fs.createWriteStream(filename, { encoding: "utf-8", autoClose: true,});
可写流事件监听
finish
:写入数据完成。error
:写入过程中发生错误。drain
:写入完成,数据管道为空。
示例代码
const fs = require("fs");const path = require("path");const filename = path.resolve(__dirname, "./3.txt");const ws = fs.createWriteStream(filename, { encoding: "utf-8", autoClose: true,});ws.on("finish", () => { console.log("写入完成");});ws.on("error", (err) => { console.log("写入错误");});
文件复制(对比流与不同读写方式)
1. 普通读写(10MB 文件复制,47ms)
这种方法先读取整个文件到内存,再从内存写入磁盘。
// 方法一:同步读写async function method1() { const from = path.resolve(__dirname, "./1.txt"); const to = path.resolve(__dirname, "./2.txt"); console.time("方式一"); const data = await fs.promises.readFile(from); await fs.promises.writeFile(to, data); console.timeEnd("方式一"); console.log("复制完成");}method1();
2. 文件流(10MB 文件复制,17ms)
利用文件流逐块读取和写入。
// 方法二:利用流function method2() { const from = path.resolve(__dirname, "./1.txt"); const to = path.resolve(__dirname, "./3.txt"); const rs = fs.createReadStream(from); const ws = fs.createWriteStream(to, { autoClose: true, }); console.time("方式二"); rs.on("data", (chunk) => { const flag = ws.write(chunk); if (!flag) { rs.pause(); } }); ws.on("drain", () => { rs.resume(); }); rs.on("close", () => { ws.end(); console.timeEnd("方式二"); console.log("复制完成"); });}method2();
3. 管道(10MB 文件复制,20ms)
通过pipe
方法实现读取流到写入流。
// 方法三:利用pipefunction method3() { const from = path.resolve(__dirname, "./1.txt"); const to = path.resolve(__dirname, "./4.txt"); const rs = fs.createReadStream(from); const ws = fs.createWriteStream(to); console.time("管道"); rs.pipe(ws); rs.on("close", () => { ws.end(); console.timeEnd("管道"); console.log("复制完成"); });}method3();
总结
文件流是一种高效的数据处理机制,特别适用于处理大文件和外部设备与内存不匹配的情况。通过使用可读流和可写流,可以实现按需读取和写入,大幅节省内存资源,并提高处理效率。
发表评论
最新留言
哈哈,博客排版真的漂亮呢~
[***.90.31.176]2025年03月21日 06时47分58秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
用ThreadLocal来优化下代码吧
2019-03-06
netcore中使用session
2019-03-06
Android 开发学习进程0.25 自定义控件
2019-03-06
多媒体文件格式全解说(下)--图片
2019-03-06
淘宝WAP版小BUG分析
2019-03-06
NodeJS+Express+MongoDB
2019-03-06
(四十四)c#Winform自定义控件-水波-HZHControls
2019-03-06
c#winform主题实现的一个方法
2019-03-06
asp.net打印网页后自动关闭网页【无需插件】
2019-03-06
一个人开发的html整站源码分享网站就这么上线了
2019-03-06
SQLServer 查看耗时较多的SQL语句(转)
2019-03-06
【计算机网络】应用层
2019-03-06
【Markdown】公式指导手册
2019-03-06
【Maven】POM基本概念
2019-03-06
【Java思考】Java 中的实参与形参之间的传递到底是值传递还是引用传递呢?
2019-03-06
【设计模式】单例模式
2019-03-06
【SpringCloud】Hystrix熔断器
2019-03-06
【Linux】2.3 Linux目录结构
2019-03-06
java.util.Optional学习笔记
2019-03-06