ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

learnyounode 实战:MY FIRST I/O 练习解析——用 fs.readFileSync 同步读取文件并统计换行数

learnyounode 实战:MY FIRST I/O 练习解析——用 fs.readFileSync 同步读取文件并统计换行数 教程CLI【免费下载链接】learnyounodeLearn You The Node.js For Much Win! An intro to Node.js via a set of self-guided workshops.项目地址https://gitcode.com/gh_mirrors/le/learnyounode点击查看免费下载本篇文章围绕 learnyounodeLearn You The Node.js For Much Win中第三个练习「MY FIRST I/O!」的土耳其语版任务文档exercises/my_first_io/problem.tr.md展开目标是用一次同步文件系统操作读取命令行参数指定的文件并向标准输出打印其包含的换行符\n数量。读完本文你将掌握 Node.js 核心fs模块的同步 API、Buffer与String的转换以及 learnyounode 自动化验证器如何从源码层面对提交代码进行行为检查从而能够独立写出并验证通过该练习。练习目标复刻cat file | wc -l原文档土耳其语版要求创建一个名为benim-ilk-io-islemim.js对应英文版任务中的my-first-io.js的 JavaScript 文件程序需要满足以下三点约束只使用一次同步senkron / blocking文件系统操作读取指定文件将该文件包含的换行符\n数量输出到控制台stdout输出结果与 Shell 命令cat file | wc -l完全一致。被读取文件的完整路径通过命令行第一个参数传入即process.argv[2]练习不要求自行构造测试文件——验证器会动态生成测试数据详见下文「验证机制」一节。从任务本质看这不仅是统计行数更是 Node.js 初学者第一次接触阻塞式 I/O与Buffer二进制数据的机会readFileSync返回的不是字符串而是Buffer而换行统计又依赖对字符串的分割逻辑中间的每一个细节都构成了本练习的知识点。前置知识fs模块与同步方法约定要完成文件系统操作必须先加载 Node.js 核心库中的fs模块。原文档给出了标准的模块加载方式const fs require(fs)fs模块是 Node.js 内置的「全局」模块无需安装第三方依赖即可使用。加载后所有文件系统能力都通过fs变量访问。fs模块中的一个重要约定是所有同步阻塞式文件系统方法都以Sync后缀结尾例如fs.readFileSync(path)——同步读取整个文件fs.writeFileSync(path, data)——同步写入文件fs.readdirSync(path)——同步读取目录列表原文档指出读取一个文件应使用fs.readFileSync(/dosya/yolu/file)该方法会返回一个Buffer对象其中包含文件的完整内容。关于fs模块的完整 API 参考可直接查看仓库内置的官方文档副本 docs-nodejs/fs.html。认识Buffer二进制数据的载体与字符串转换这是本练习最核心的进阶知识点。Buffer是 Node.js 高效表达任意连续数据序列的方式数据可以是 ASCII、二进制或其他任意格式——这正是文件内容的天然形态。原文档强调Buffer对象可通过调用其toString()方法轻松转换为字符串例如const str buf.toString()转换后的字符串才能进行文本层面的处理如按\n分割。仓库内置的 docs-nodejs/buffer.html 提供了关于Buffer的完整文档适合进一步深入包括Buffer.from()、编码参数utf8、ascii、base64等、以及buffer.length与字符串length的差异等。值得注意的是readFileSync的第二个可选参数可以直接指定编码。从官方参考答案exercises/my_first_io/solution/solution.js的注释可以看到这种等价写法// 直接传入 utf8 作为第二个参数返回的就是 String 而非 Buffer fs.readFileSync(process.argv[2], utf8).split(\n).length - 1两种写法都正确前者显式体现「Buffer → String」的转换过程后者更简洁。换行计数split(\n)与「多一个元素」的边界陷阱统计换行数的最简方式是使用 JavaScript 字符串的.split()方法以\n作为分隔符将字符串拆成子字符串数组。但原文档特别提醒了一个极易踩坑的细节测试文件的最后一行末尾不含\n字符因此直接split(\n)得到的数组会比实际换行数多一个元素。例如内容为a\nb\nc共 2 个换行的字符串split(\n)会得到[a, b, c]——3 个元素。所以正确的行数计算公式是const lines contents.toString().split(\n).length - 1减去的这 1正是因为文件末尾没有以换行符结尾而多出的那个「空尾巴」。如果文件末尾恰好有换行如a\nb\nsplit(\n)得到[a, b, ]长度 3减 1 后仍为 2公式同样成立——这个技巧对所有文本文件都稳健。参考实现与逐步注释仓库提供了官方参考实现 exercises/my_first_io/solution/solution.js完整代码如下use strict const fs require(fs) const contents fs.readFileSync(process.argv[2]) const lines contents.toString().split(\n).length - 1 console.log(lines) // note you can avoid the .toString() by passing utf8 as the // second argument to readFileSync, then youll get a String! // // fs.readFileSync(process.argv[2], utf8).split(\n).length - 1逐行解读代码作用const fs require(fs)加载 Node 核心fs模块process.argv[2]取命令行第 3 个参数前两个固定为node与脚本路径即待读文件的完整路径fs.readFileSync(...)同步读取整个文件返回Buffer阻塞直到文件读完.toString().split(\n).length - 1Buffer 转字符串 → 按换行符拆分 → 元素数减 1 得到换行数console.log(lines)将结果输出到 stdout行为与cat file | wc -l一致仓库还为多种语言维护了等价参考实现例如 exercises/my_first_io/solution_zh-cn/solution.js中文注释版本、solution_fr、solution_ja等逻辑完全相同可作为对照阅读。验证机制验证器如何从源码层检查你的提交learnyounode 的每个练习都带有一个验证器。本练习的验证器位于 exercises/my_first_io/exercise.js其工作流程揭示了这个练习真正考核的行为标准1. 动态生成测试文件addSetup验证器在run/verify两种模式下都会先生成一个随机测试文件行数由Math.ceil(Math.random() * 50)决定150 行内容由boganipsum生成器产生随机英文段落文本文件写入系统临时目录os.tmpdir()下以_learnyounode_pid.txt命名随后通过submissionArgs.unshift(testFile)将文件路径注入为待测程序的process.argv[2]。这就是为什么原文档说「你不需要自己构造测试文件」。2. 拦截 fs 调用wrappedexecwrap练习通过 exercises/my_first_io/wrap.js 对被提交的程序进行「包装」它遍历fs、fs.promises、util上的全部方法用代理函数替换并通过栈回溯$captureStack判断调用是否来自主程序。凡是主程序发起的fs方法调用都会被记录到ctx.fsCalls中——即验证器可以精确知道你的程序到底调用了哪些 fs API。3. 校验「必须同步、禁止异步」addVerifyProcessorObject.keys(exercise.wrapData.fsCalls || {}).forEach(function (m) { if (/Sync$/.test(m)) { usedSync true this.emit(pass, this.__(pass.sync, { method: fs. m () })) } else { usedAsync true this.emit(fail, this.__(fail.async, { method: fs. m () })) } }.bind(this)) callback(null, !usedAsync usedSync)这段逻辑是练习的判分核心只要提交的程序调用过任何不带Sync后缀的异步 fs 方法如fs.readFile、fs.readFileSync的 promise 变体fs.promises.readFile就会判定失败只有全部使用同步方法方法名匹配/Sync$/才算通过。最终结果由!usedAsync usedSync决定。4. 清理addCleanup无论通过与否验证结束后都会用rimraf删除临时生成的测试文件不留下垃圾。测试用例通过正反样例理解评判标准仓库 test/my_first_io 目录提供了该练习的验证样本是理解评分逻辑的最佳教材valid_01.js使用fs.readFileSync(process.argv[2])同步读取函数封装后计算换行数并打印——应通过。invalid_01.js使用fs.readFile异步回调版本读取文件。虽然输出结果可能正确但触碰了「禁止异步」的红线验证器会判定失败。invalid_02.js只console.log(1)从未调用任何 fs 方法——usedSync为 false判定失败。invalid_03.js虽然使用了同步readFileSync但硬编码输出-1未真正统计换行数——结果错误判定失败。这组用例印证了练习的双重考核维度既要求用对 API同步而非异步也要求算对结果真实统计而非伪造。初学者常见的错误模式基本都覆盖在这四个样例中。运行与验证完整命令行操作完成benim-ilk-io-islemim.js后在原文档给出的命令中{appname}是一个占位符。从项目入口 learnyounode.js 可以看出该练习由 workshopper-adventure 框架注册练习列表中的第三项MY FIRST I/O!CLI 应用名即learnyounode。因此实际验证命令为$ learnyounode verify benim-ilk-io-islemim.js若只想先手动运行看看效果验证器同样会生成随机测试文件并作为参数传入可执行$ learnyounode run benim-ilk-io-islemim.js也可以脱离 learnyounode直接用自己的文件验证程序行为$ node benim-ilk-io-islemim.js /etc/hostname $ cat /etc/hostname | wc -l # 两者输出应一致小结一次同步读取背后的完整知识链「MY FIRST I/O!」虽然代码量极小却串联起 Node.js 入门的四条主线模块加载require(fs)、同步 I/O 约定Sync后缀、二进制数据抽象Buffer与toString()转换、字符串边界处理split(\n)的数组多一元素陷阱。而 learnyounode 的验证器exercises/my_first_io/exercise.js通过运行时包装与调用栈分析从源码层面强制约束「必须用同步 API」让初学者在通关的同时建立起对阻塞式文件 I/O 的直觉。后续的「MY FIRST ASYNC I/O!」练习将在此基础上引入异步回调形成完整的对比认知链条。赞分享教程CLI【免费下载链接】learnyounodeLearn You The Node.js For Much Win! An intro to Node.js via a set of self-guided workshops.项目地址https://gitcode.com/gh_mirrors/le/learnyounode点击查看免费下载相关推荐learnyounode MY FIRST I/O!用 fs.readFileSync 同步读取文件并统计换行数learnyounode MY FIRST I/O!用 fs.readFileSync 同步读取文件并统计换行数 本篇技术指南围绕 learnyounode教程CLIlearnyounode 实战用 fs.readFile() 异步读取文件并统计行数MY FIRST ASYNC I/O!learnyounode 实战用 fs.readFile 异步读取文件并统计行数MY FIRST ASYNC I/O! 本篇技术指南以 learnyoun教程CLISerial Studio 连接诊断深入解析Spec 0035 的即时 探测双轨检查体系、API 契约与源码实现Serial Studio 连接诊断深入解析Spec 0035 的即时 探测双轨检查体系、API 契约与源码实现 本篇基于 Serial Studio 的教程CLI上一篇Depth-Anything-V2终极指南如何用Transformer实现精准单目深度估计下一篇如何快速部署WVP-GB28181-Pro面向初学者的完整国标视频监控平台搭建指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表