learnyounode 实战:用 `fs.readFile()` 异步读取文件并统计行数(MY FIRST ASYNC I/O!)
发布时间:2026/9/29 2:37:10 锦皓数字建站
` 异步读取文件并统计行数(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 ASYNC I/O!仓库路径exercises/my_first_async_io/为核心讲解如何用 Node.js 风格的异步文件系统操作读取文件并在 stdout 输出其换行数行为等价于cat file | wc -l。读完本文你将掌握fs.readFile()回调式 API 的用法、Node.js 惯用回调签名function callback (err, data)的含义、Buffer与String两种读取结果的选择以及 learnyounode 是如何在自动化校验中区分同步/异步实现的——并最终通过learnyounode verify的检验。练习背景从同步到异步的 The Node.js way本练习位于 learnyounode 13 个自导式工作坊练习序列中的第 4 个注册顺序见 learnyounode.js其直接前身是第 3 个练习 MY FIRST I/O!exercises/my_first_io/problem.md。两者的题目几乎相同——读取命令行参数指定的文件打印文件中的换行数区别只有一个前一个练习要求使用同步blocking的fs.readFileSync()而本练习必须采用异步的fs.readFile()。原题目标来自exercises/my_first_async_io/problem.md如下创建文件my-first-async-io.js用单个异步文件系统操作读取文件并将文件包含的换行数打印到控制台stdout待读取文件的完整路径由第一个命令行参数提供。之所以说解法几乎与前一个问题相同是因为行数统计的核心算法完全一致唯一的变化是把用返回值拿数据改为从回调参数里拿数据。这正是学习本练习的核心价值理解 Node.js 事件循环下不阻塞、靠回调返回结果的编程范式。核心知识点一fs.readFile()与回调式 API在同步解法中fs.readFileSync()会返回一个包含文件全部内容的Buffer对象代码可以立即使用返回值。而异步的fs.readFile()不会返回文件内容数据只能从你传入的回调函数中获取// 同步直接使用返回值 const contents fs.readFileSync(/path/to/file) // 异步从回调参数中收集数据 fs.readFile(/path/to/file, function (err, data) { // 在这里使用 data })Node.js 惯用的回调签名是function callback (err, data) { /* ... */ }因此你可以通过检查第一个参数err是否为真值truthy来判断是否出错若没有错误第二个参数就是文件内容。两种取值形态Buffer还是Stringfs.readFile()支持两种调用形式这是原文档重点强调的细节调用形式回调第二参数类型说明fs.readFile(file, callback)Buffer默认返回原始字节缓冲需要.toString()转换fs.readFile(file, utf8, callback)String指定字符编码后直接得到字符串本练习的官方参考解法solution.js展示了两种写法use strict const fs require(fs) const file process.argv[2] fs.readFile(file, function (err, contents) { if (err) { return console.log(err) } // fs.readFile(file, utf8, callback) can also be used const lines contents.toString().split(\n).length - 1 console.log(lines) })要点拆解process.argv[2]是第一个命令行参数即文件完整路径process.argv[0]、process.argv[1]分别是 node 与脚本路径代码先做err检查再通过contents.toString()把Buffer转为字符串若要省去.toString()可以直接把utf8作为第二个参数、回调作为第三个参数此时第二参数就是String。核心知识点二如何准确统计换行数统计换行数的技巧与前一个练习完全一致把字符串用\n作分隔符.split()成数组数组长度减 1就是换行数const lines contents.toString().split(\n).length - 1 console.log(lines)为什么是长度减 1因为原文档明确说明测试文件最后一行末尾没有换行符split(\n)之后得到的数组元素个数会比换行数多 1。例如内容a\nb\nc会切分成[a, b, c]长度 3而换行数是 2。这一点在exercises/my_first_io/problem.md中也有同样的说明属于两个练习共用的计数约定。核心知识点三用learnyounode verify自动校验编写完程序后运行以下命令校验正确性{appname}即 learnyounode 命令$ learnyounode verify my-first-async-io.js也可以先运行learnyounode run my-first-async-io.js观察程序的输出效果再进入验证流程。校验器如何判定异步实现本练习的校验器exercise.js不只是比对输出结果它还会静态检测你的代码到底用了同步还是异步 API。其工作流程如下准备随机测试文件addSetup阶段用boganipsum生成 1 到 50 段随机文本Math.ceil(Math.random() * 50)写入系统临时目录下名为_learnyounode_pid.txt的文件并把该文件路径通过submissionArgs.unshift(testFile)注入为你的程序的第一个命令行参数。运行时埋点校验器把 ../my_first_io/wrap.js 作为包装模块注入子进程对所有fs模块方法包括fs.promises与util做包装当你的主程序调用某个 fs 方法时通过调用栈ctx.$captureStack判断调用方是否是你的主程序文件并记录在ctx.fsCalls中。验证阶段判定addVerifyProcessor遍历exercise.wrapData.fsCalls中记录到的所有 fs 方法调用——凡是以Sync结尾的方法如readFileSync即触发fail.sync失败提示反之记为异步调用累计pass.async通过提示。最终只有当存在异步调用且不存在任何同步调用usedAsync !usedSync时练习才算通过。清理无论 run 还是 verify结束后都会用rimraf删除临时测试文件。这套机制说明本练习的验收标准是必须走异步路径即使输出结果正确只要使用了fs.readFileSync()也会被判失败。测试用例佐证仓库test/my_first_async_io/目录下的用例与上述逻辑一一对应valid_01.js使用fs.readFile(process.argv[2], countNewLines)的异步实现回调内先检查error再统计行数并输出是通过样例invalid_01.js使用fs.readFileSync()同步读取的反例结果正确也会因同步 API 被判无效invalid_02.js虽然用了异步fs.readFile()但回调里固定输出-1结果错误的失败样例。完整可运行实现与常见错误推荐解法直接给回调函数const fs require(fs) const file process.argv[2] fs.readFile(file, utf8, function (err, contents) { if (err) { return console.log(err) } const lines contents.split(\n).length - 1 console.log(lines) })命名函数写法更易读const fs require(fs) fs.readFile(process.argv[2], countNewLines) function countNewLines (error, text) { if (error) { return console.log(error) } const lineCount text.toString().split(\n).length - 1 console.log(lineCount) }与测试用例 valid_01.js 同构必须避开的三个坑把回调写成同步返回fs.readFile()没有返回值可用内容只存在于回调参数中漏掉err检查惯用回调约定第一参数是错误对象若文件不存在例如路径拼错而你不检查err后续处理contents会崩溃误用同步 API即使fs.readFileSync()输出的行数完全正确也会被本练习的校验器判为失败见上文invalid_01.js。延伸阅读fs模块的完整 API 文档readFile、readFileSync、回调约定、编码参数可在仓库内置文档 docs-nodejs/fs.html 中查阅Buffer对象的转换与操作说明见 docs-nodejs/buffer.html本练习的前身同步版题目见 exercises/my_first_io/problem.md其中对Buffer、toString()与换行计数原理有更详尽的铺垫想继续学习下一练习 FILTERED LSexercises/filtered_ls/会在此基础上引入fs.readdir与路径过滤进一步加深异步编程实践。赞分享教程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点击查看免费下载相关推荐Serial Studio 连接诊断深入解析Spec 0035 的即时 探测双轨检查体系、API 契约与源码实现Serial Studio 连接诊断深入解析Spec 0035 的即时 探测双轨检查体系、API 契约与源码实现 本篇基于 Serial Studio 的教程CLIlearnyounode 实战用 fs.readFile 异步回调统计文件行数MY FIRST ASYNC I/O 习题全解learnyounode 实战用 fs.readFile 异步回调统计文件行数MY FIRST ASYNC I/O 习题全解 本指南以 learnyoun教程CLIdcg allowlist 信任层级详解为什么项目白名单默认不生效AI 命令守卫 3 层优先级全解析dcg allowlist 信任层级详解为什么项目白名单默认不生效AI 命令守卫 3 层优先级全解析 dcgDestructive Command Gua教程CLI上一篇如何在Android/iOS/桌面端快速集成KoalaPlot跨平台图表开发实战下一篇前端无障碍开发la-velada-web-oficial键盘导航实现创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。