谈谈 Node.js 中的文件系统(fs)模块,如何进行文件读写操作?
Node.js 文件系统(fs)模块深度解析与实践指南
一、模块基础与核心能力
Node.js 的 fs 模块提供了完整的文件系统操作能力,涵盖 50+ 个方法,主要分为以下类型:
- 文件读写:基础 CRUD 操作
- 目录操作:创建/删除/遍历目录
- 文件监控:watch/watchFile 方法
- 文件信息:stat/access 等方法
- 流式处理:createReadStream/createWriteStream
// 基础引入方式
const fs = require('fs');// 推荐使用 Promise 版本
const fsp = require('fs').promises;
二、文件读写核心方法对比
| 方法类型 | 同步方法 | 异步回调 | Promise 版本 |
|---|---|---|---|
| 文件读取 | readFileSync | readFile | promises.readFile |
| 文件写入 | writeFileSync | writeFile | promises.writeFile |
| 追加写入 | appendFileSync | appendFile | promises.appendFile |
| 流式读取 | 无 | createReadStream | 无 |
| 流式写入 | 无 | createWriteStream | 无 |
三、基础文件操作实践
1. 同步方式(慎用)
// 文件读取
try {const data = fs.readFileSync('config.json', 'utf8');console.log('配置文件内容:', data);
} catch (err) {console.error('读取配置文件失败:', err);
}// 文件写入
try {fs.writeFileSync('log.txt', `${new Date()} 系统启动\n`, { flag: 'a' });
} catch (err) {console.error('日志写入失败:', err);
}
2. 异步回调方式
// 读取后写入的链式操作
fs.readFile('source.txt', 'utf8', (err, data) => {if (err) return console.error('读取失败:', err);fs.writeFile('dest.txt', data.toUpperCase(), err => {err ? console.error('写入失败:', err) : console.log('文件转换完成');});
});
3. Promise 方式(推荐)
// 使用 async/await 处理
async function processFile() {try {const content = await fsp.readFile('template.html', 'utf8');const processed = content.replace('{{title}}', '首页');await fsp.writeFile('dist/index.html', processed);console.log('HTML 生成完成');} catch (err) {console.error('文件处理失败:', err);}
}// 并行处理多个文件
async function batchProcess() {try {const [a, b] = await Promise.all([fsp.readFile('a.txt'),fsp.readFile('b.txt')]);await fsp.writeFile('combined.txt', Buffer.concat([a, b]));} catch (err) {console.error('批量处理失败:', err);}
}
四、高级文件操作技巧
1. 流式处理大文件
// 高效的大文件复制
function copyLargeFile(source, target) {return new Promise((resolve, reject) => {const rs = fs.createReadStream(source);const ws = fs.createWriteStream(target);rs.on('error', reject).pipe(ws).on('finish', resolve).on('error', reject);});
}// 使用示例
copyLargeFile('4k-video.mp4', 'copy.mp4').then(() => console.log('大文件复制完成')).catch(console.error);
2. 文件监控实践
// 监控配置文件变化
const watcher = fs.watch('config.ini', (eventType, filename) => {if (eventType === 'change') {console.log(`配置文件 ${filename} 被修改`);// 重新加载配置loadConfig();}
});// 错误处理
watcher.on('error', err => {console.error('文件监控异常:', err);
});
3. 精准控制文件操作
// 使用文件描述符
async function writeWithDescriptor() {let fd;try {// 打开文件获取描述符fd = await fsp.open('data.log', 'a');// 精准写入位置await fsp.write(fd, Buffer.from('新日志\n'), 0, 'utf8');// 获取文件状态const stats = await fsp.fstat(fd);console.log('当前文件大小:', stats.size);} finally {if (fd) await fd.close();}
}
五、实战建议与避坑指南
1. 路径处理规范
// 使用 path 模块处理路径
const path = require('path');// 正确做法
const fullPath = path.join(__dirname, 'data', 'file.txt');// 危险做法(路径拼接问题)
const badPath = './data/' + fileName;
2. 错误处理要点
// 典型的错误处理反模式
fs.readFile('data.txt', (err, data) => {if (err) throw err; // 错误会直接导致进程崩溃// ...处理逻辑
});// 正确的错误处理方式
fs.readFile('data.txt', (err, data) => {if (err) {console.error('读取失败:', err);// 根据错误类型处理if (err.code === 'ENOENT') {return createDefaultFile();}return;}// ...正常逻辑
});
3. 性能优化建议
// 批量写入优化
async function writeLogs(messages) {const fd = await fsp.open('app.log', 'a');try {// 合并写入减少IO次数const buffer = Buffer.from(messages.join('\n') + '\n');await fsp.write(fd, buffer);} finally {await fd.close();}
}
六、企业级开发建议
- 环境区分处理
// 开发环境使用内存文件系统加速测试
if (process.env.NODE_ENV === 'test') {const { vol } = require('memfs');module.exports = vol;
} else {module.exports = require('fs');
}
- 增强模块选择
// 使用 fs-extra 扩展功能
const fse = require('fs-extra');// 目录复制示例
fse.copy('/source', '/dest').then(() => console.log('目录复制成功')).catch(err => console.error('复制失败:', err));
- 文件锁机制
// 使用 proper-lockfile 处理并发
const lockfile = require('proper-lockfile');async function safeWrite() {const release = await lockfile.lock('data.json');try {await fsp.writeFile('data.json', newData);} finally {await release();}
}
七、典型问题排查指南
- EMFILE 错误处理
// 使用 graceful-fs 解决文件描述符耗尽问题
const gracefulFs = require('graceful-fs');
gracefulFs.gracefulify(fs);
- 内存溢出分析
// 错误的大文件处理方式
app.get('/bigfile', async (req, res) => {const data = await fsp.readFile('huge-file.zip'); // 可能造成内存溢出res.send(data);
});// 正确方式使用流处理
app.get('/bigfile', (req, res) => {const rs = fs.createReadStream('huge-file.zip');rs.pipe(res);
});
- 权限问题处理
// 检查文件权限
async function checkPermissions() {try {await fsp.access('config.xml', fs.constants.R_OK | fs.constants.W_OK);} catch (err) {if (err.code === 'EACCES') {console.error('文件权限不足');// 尝试修复权限await fsp.chmod('config.xml', 0o644);}}
}
八、总结与最佳实践
- 方法选择策略
- 常规操作:优先使用 fs.promises 方法
- 配置加载:可使用同步方法(仅在启动阶段)
- 大文件处理:必须使用流式操作
- 批量操作:结合 Promise.all 和适当并发控制
- 性能优化关键点
- 减少不必要的文件操作
- 合并小文件写入
- 使用内存文件系统进行测试
- 合理设置缓冲区大小(highWaterMark)
- 安全注意事项
- 验证用户输入的文件路径
- 防止目录遍历攻击
- 文件操作后及时关闭描述符
- 敏感文件设置适当权限
通过合理选择文件操作方法,结合错误处理和性能优化策略,可以有效构建健壮的Node.js文件操作模块。记住:文件操作无小事,特别是在生产环境中,务必做好日志记录、权限控制和异常监控。
相关文章:
谈谈 Node.js 中的文件系统(fs)模块,如何进行文件读写操作?
Node.js 文件系统(fs)模块深度解析与实践指南 一、模块基础与核心能力 Node.js 的 fs 模块提供了完整的文件系统操作能力,涵盖 50 个方法,主要分为以下类型: 文件读写:基础 CRUD 操作目录操作࿱…...
Python Cookbook-2.18 从指定的搜索路径寻找文件
任务 给定一个搜索路径(一个描述目录信息的字符串),需要根据这个路径和请求的文件名找到第一个符合要求的文件。 解决方案 需要循环指定的搜索路径中的目录: import os def search_file(filename,search path,pathsepos.pathsep): """…...
安装Git(小白也会装)
一、官网下载:Git 1.依次点击(红框) 不要安装在C盘了,要炸了!!! 后面都 使用默认就好了,不用改,直接Next! 直到这里,选第一个 这两种选项的区别如…...
工学一体化教育模式的核心内涵及实践意义探究
工学一体化是一种将理论教学与实践操作深度融合的教育模式,旨在通过工作过程与学习过程的有机结合,培养具备综合职业能力和创新能力的技能人才。 一、工学一体化的核心内涵 工学一体化教学模式强调“在工作中学习、在学习中工作”,其核心在于…...
前端正则表达式完全指南:从入门到实战
文章目录 第一章:正则表达式基础概念1.1 什么是正则表达式1.2 正则表达式工作原理1.3 基础示例演示 第二章:正则表达式核心语法2.1 元字符大全表2.2 量词系统详解2.3 字符集合与排除 第三章:前端常用正则模式3.1 表单验证类3.1.1 邮箱验证3.1…...
Chromium项目相关
Chromium项目相关 Chromium 是一个开源浏览器项目,旨在为所有用户构建一种更安全、更快速、更稳定的方式来体验 Web。 自 Google 在 2008 年宣布 Chromium 项目以来,他们一直很高兴能够在开源 Web 浏览器的良好基础上进行构建,并为富 Web 平…...
自动驾驶测试场景相关概念
自动驾驶测试场景 一、概念二、分类2.1、按照场景的抽象程度可分为:功能场景、逻辑场景、具体场景。2.2.、按功能划分2.3、 按环境复杂度2.3、按场景类型 三、要素四、挑战与趋势4.1、长尾场景覆盖4.2、伦理决策测试4.3、车路协同测试4.4、联邦学习驱动…...
给小白的oracle优化工具,了解一下
有时懒得分析或语句太长,可以尝试用oracle的dbms_sqldiag包进行sql优化, --How To Use DBMS_SQLDIAG To Diagnose Query Performance Issues (Doc ID 1386802.1) --诊断SQL 性能 SET ECHO ON SET LINESIZE 132 SET PAGESIZE 999 SET LONG 999999 SET SER…...
DMA发送全部历史记录数据到串口
背景 博主参与的项目中,有个读取全部历史记录的功能,如果下位机在主程序中将全部历史记录单纯地通过串口传输会比较占用cpu资源,影响主程序中别的功能。最后商量得出以下实现方案: 定义两个发送缓冲区DMATxbuf1和DMATxbuf2&…...
基因型—环境两向表数据分析——品种生态区划分
参考资料:农作物品种试验数据管理与分析 用于品种生态区划分的GGE双标图有两种功能图:试点向量功能图和“谁赢在哪里”功能图。双标图的具体模型基于SD定标和h加权和试点中心化的数据。本例中籽粒产量的GGE双标图仅解释了G和GE总变异的53.6%,…...
电路中如何计算电容容值大小
一个例题: 【电路中电容容值是怎么算出来的?】https://www.bilibili.com/video/BV1RQ4y1c7i1?vd_source3cc3c07b09206097d0d8b0aefdf07958...
c++中迭代器和指针有什么区别?
在 C 中,迭代器和指针虽然在某些场景下有相似的行为,但它们在设计目的、功能和使用场景上有本质区别。以下是详细对比和最佳实践: 一、核心区别对比表 特征指针迭代器本质原生数据类型,直接存储内存地址类对象,抽象容…...
GPT大语言模型与搜索引擎:技术本质与应用场景的深度解析
引言 在人工智能和自然语言处理(NLP)领域,GPT(Generative Pre-trained Transformer)大语言模型和搜索引擎是两个备受关注的技术。尽管它们都涉及到信息检索和生成,但它们在技术原理、应用场景和用户体验上…...
FreeRTOS-中断管理
实验目的 创建一个队列及一个任务,按下按键 KEY1 触发中断,在中断服务函数里向队列里发送数据,任务则阻塞接 收队列数据。 实验代码 实验结果 这样就实现了,使用中断往队列的发送信息,用任务阻塞接收信息...
计算机毕业设计SpringBoot+Vue.js音乐网站(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
更换k8s容器运行时环境为docker
更换k8s容器运行时环境为docker k8s-V1.24之后容器运行时默认是containerd,若想改为熟悉的docker作为运行时,需要做以下操作 在每个节点安装containerd、docker; 每个节点安装cri-docker; 调整kubelet配置并重启验证。 1.安装docker、con…...
知识图谱-资源网
知识图谱-资源网 http://openkg.cn/datasets-type/https://www.ownthink.com/knowledge.html...
CTF-web: Rust 的过程宏
Rust 的过程宏(Procedural Macros)是一种强大的元编程工具,允许你在编译时对代码进行操作和生成。与属性宏和派生宏不同,过程宏可以接收并处理任意 Rust 代码,生成新的代码片段。这里有一个简单的例子来说明 Rust 的过…...
小程序Three Dof识别 实现景区AR体验
代码工程 GitCode - 全球开发者的开源社区,开源代码托管平台 dof...
Windows 11 下正确安装 Docker Desktop 到 D 盘的完整教程
文章目录 Windows 11 在 D 盘正确安装 Docker Desktop 的完整教程**前言****准备工作****1. 手动创建 Docker 相关目录**(⚠️ **这一步非常重要**,否则会报错)**2. 下载 Docker Desktop 安装程序****3. 使用管理员权限打开终端** **安装 Doc…...
锐评当前主流的各大编程语言
喵~ 让本喵来爪爪锐评一波编程语言吧!(ฅ•ω•ฅ)✧ 🐍 Python “简单到能拿爪子写代码喵~” 但缩进强迫症克星!写起来像在撸猫,跑起来…有时候像猫主子突然打翻水杯(GIL锁警告)~ 库多到能埋人࿰…...
2.数据结构:1.Tire 字符串统计
1.Tire 字符串统计 #include<algorithm> #include<cstring> #include<iostream>using namespace std;const int N100010; int son[N][26];//至多 N 层,每一层至多 26 个节点(字母) int cnt[N];//字符串至多 N 个ÿ…...
2020 年英语(一)考研真题 笔记(更新中)
Section I Use of English(完型填空) 原题 Directions:Read the following text. Choose the best word (s) for each numbered blank and mark A, B, C or D on the ANSWER SHEET. (10 points) Even if families are less likely to si…...
YOLO11改进加入ResNet网络
文章目录 1.改进目的2.demo引入2.1代码2.2 结果展示2.3 BottleNeck详解 1.改进目的 原始YOLO11模型训练好以后,检测结果mAP结果很低,视频检测结果很差,于是想到改进网络,这里介绍改进主干网络。 2.demo引入 2.1代码 # File: 2…...
硬编码(三)经典变长指令一
我们在前两节的硬编码中学习了定长指令,接下来学习变长指令 对于定长指令,我们通过opcode便可知该指令的长度,但是对于变长指令却是不可知的。变长指令长度由opcode,ModR/M,SIB共同决定。变长指令通常在需要操作内存的…...
在线VS离线TTS(语音合成芯片)有哪些优势-AIOT智能语音产品方案
离线 TTS 存在语音质量欠佳、音色选择有限、语言支持单一更新困难、占用资源多、适应性差、难以个性化定制等痛点 01更新维护困难 由于是离线模式,难以及时获取最新的语音数据和算法更新,无法得到持续改进。 02占用本地资源 需要在设备本地存储较大的…...
【Spring Boot】掌握 Spring 事务:隔离级别与传播机制解读与应用
前言 ???本期讲解关于spring 事务传播机制介绍~~~ ??感兴趣的小伙伴看一看小编主页:-CSDN博客 ?? 你的点赞就是小编不断更新的最大动力 ??那么废话不多说直接开整吧~~ 目录 ???1.事务的隔离级别 ??1.1MySQL事务隔离级别 ??1.2Spring事务隔离…...
PySide(PyQT)重新定义contextMenuEvent()实现鼠标右键弹出菜单
在 PySide中,contextMenuEvent() 是 QWidget 类(以及继承自它的所有子类)的一个事件处理方法,主要用于处理上下文菜单事件,也就是当用户在控件上右键点击时触发的事件。 • 通过重新定义contextMenuEvent()来实现自定…...
Redis 持久化方式:RDB(Redis Database)和 AOF(Append Only File)
本部分内容是关于博主在学习 Redis 时关于持久化部分的记录,介绍了 RDB 和 AOF 两种持久化方式,详细介绍了持久化的原理、配置、使用方式、优缺点和使用场景。并对两种持久化方式做了对比。文章最后介绍了 Redis 持久化的意义并与其他常见的缓存技术做了…...
数据库测试
TPCH 22条SQL语句分析 - xibuhaohao - 博客园 TPCH模型规范、测试说明及22条语句 - zhjh256 - 博客园 TPC-DS 性能比较:TiDB 与 Impala-PingCAP | 平凯星辰 揭秘Oracle TPC-H性能优化:如何提升数据库查询速度,揭秘实战技巧与挑战 引言 T…...
