diff --git "a/\345\205\250\344\277\212\346\236\227/20260307-\345\210\235\350\257\206Node.js.md" "b/\345\205\250\344\277\212\346\236\227/20260307-\345\210\235\350\257\206Node.js.md" new file mode 100644 index 0000000000000000000000000000000000000000..1f040fc2a16dd9f1160e0a9862875afed900e87b --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20260307-\345\210\235\350\257\206Node.js.md" @@ -0,0 +1,53 @@ +## 笔记: + +|知识点 |关键内容| +|---|---:| +|Node.js定义 | 基于Chrome V8引擎的JavaScript运行时| +|单线程 | 一个线程处理所有请求,节省资源| +|非阻塞I/O | I/O操作时不等待,继续执行其他任务| +|事件驱动 | 通过事件和回调处理异步操作| +|应用场景 | Web服务器、API服务、实时通信、命令行工具| + +##### Node.js = V8引擎(执行JavaScript)+ libuv(处理I/O) + +--- + +核心优势: +- 高性能(V8引擎) +- 高并发(非阻塞I/O) +- 前后端同语言(JavaScript) +- 丰富的npm生态 + +## 作业: +### 选择题 +1. Node.js是基于V8JavaScript引擎开发的 +2. 多线程是Node.js的核心特性 +3. Node.js适合开发实时聊天系统 +4. Ryan Dahl是Node.js的创始人 +5. Node.js中的"I/O"主要指Input/Output(输入/输出) + + +## 简答题: +### 什么是Node.js? +答: +Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,支持事件驱动和非阻塞 I/O 模型,具有高效、轻量的特点。 + +请解释"非阻塞I/O"是什么意思,它有什么优点? +答: +官方回答 +阻塞I/O:在进行I/O操作时,进程会被阻塞,直到数据准备好并复制到进程的缓冲区中才返回。 + +非阻塞I/O:当I/O操作会导致进程阻塞时,该调用会立即返回一个错误,进程可以继续执行其他任务。 +自己的理解:不会影响你当时要做的事情就比如说我现在在敲代码刚好到饭点我需要吃饭,我只需要点一个外卖就可以继续敲我的代码而不是要我自己停下来去做饭。 + +### 为什么Node.js适合开发实时聊天应用? +答: +Node.js 基于 Google 的 V8 JavaScript 引擎构建,该引擎以其高性能而著称。这使得 Node.js 成为构建需要速度和可扩展性的实时通信应用程序的完美工具。Node.js 还是事件驱动型的,这意味着它可以同时处理多个连接,使其成为构建实时应用程序的完美工具。 + +### 请列举Node.js的3个应用场景 +答: + 微信 qq 淘宝 + +### Node.js和传统后端语言(如Java、PHP)相比,有什么优势? +答: +Node.js、Java和PHP作为当前最流行的后端开发语言,各自拥有独特的优势和局限性。 本文将从性能、适用场景、优缺点等多个维度,深入对比这三门语言,帮助开发者做出更明智的选择。 异步非阻塞I/O模型:Node.js采用事件驱动、非阻塞I/O模型,使其在处理大量并发请求时表现出色。 这种模型能够充分利用系统资源,减少线程切换和同步调用的开销,从而提高服务器的吞吐量和响应速度。 统一的编程语言:Node.js允许开发者使用JavaScript进行前后端全栈开发,降低了开发难度和学习成本,提高了开发效率。 \ No newline at end of file diff --git "a/\345\205\250\344\277\212\346\236\227/20260308-\346\220\255\345\273\272\345\274\200\345\217\221\347\216\257\345\242\203\351\200\211\346\213\251\351\242\230.md" "b/\345\205\250\344\277\212\346\236\227/20260308-\346\220\255\345\273\272\345\274\200\345\217\221\347\216\257\345\242\203\351\200\211\346\213\251\351\242\230.md" new file mode 100644 index 0000000000000000000000000000000000000000..e140879ac590fbf82afd7facc6edb84dc67b9d1f --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20260308-\346\220\255\345\273\272\345\274\200\345\217\221\347\216\257\345\242\203\351\200\211\346\213\251\351\242\230.md" @@ -0,0 +1,48 @@ +### 选择题 +### Node.js的LTS版本是什么意思?目前最新的LTS版本是哪个? +1. + + LTS 是 Long-Term Support(长期支持) 的缩写,是 Node.js 官方为企业级、生产环境应用提供的版本类型,核心特点如下: + +- 稳定性优先:LTS 版本会经过充分的测试和验证,不会包含实验性特性,避免因功能迭代引入新问题,适合对稳定性要求高的生产环境。 +- 长期维护支持:官方会为 LTS 版本提供长达数年的支持(分为「Active LTS(活跃支持)」和「Maintenance LTS(维护支持)」阶段),包括安全补丁、关键 bug 修复,但不会新增功能。 +- 对比非 LTS 版本:Node.js 还有「Current(当前)」版本(也叫稳定版),会包含最新功能,但支持周期短(仅 6 个月),适合开发、测试环境,不建议生产环境使用。 + +2. + + Node.js 官方最新的 LTS 版本是 Node.js 20.x(代号 Iron) +### npm是用来做什么的? + 答:npm是用来管理Node.js包 + +### 初始化Node.js项目的命令是? + 答:npm init +### 运行Node.js程序的命令是? + 答:node app.js +### package.json文件主要记录什么信息? + 答:package.json 是 Node.js/ 前端项目的标配配置文件,本质是一个 JSON 格式的文本文件,它集中记录了项目的所有核心元信息和依赖配置,包管理器(npm/yarn/pnpm)会根据这个文件识别项目、安装依赖、运行脚本等。 +### 请解释LTS版本和Current版本有什么区别? +答: + + 1. + 核心差异:LTS 版本侧重稳定和长期维护,适合生产环境;Current 版本侧重新功能,仅短期维护,适合开发 / 测试; + 2. + + 维护周期:LTS 总计维护 30 个月,Current 仅维护 6 个月; + 3. + + 选择原则:生产用 LTS,开发可按需选 Current,新手优先 LTS。 +### npm和Node.js是什么关系? + 答:Node.js 是运行环境,npm 是随 Node.js 一起安装的包管理工具。 +### package.json文件中的dependencies和devDependencies有什么区别? + 答:dependencies 是项目运行时必须的依赖(生产环境要用),devDependencies 是仅开发 / 测试阶段需要的依赖(生产环境用不上)。 +### VSCode有哪些特点让它适合开发Node.js? + 答:VS Code = 写 Node.js 的 “官方标配编辑器” + 自带终端 + 智能提示 + 调试 + 插件生态,让 Node.js 开发最简单、最快、最不容易出错 +### 请描述在Windows上安装Node.js的步骤。 + + 答: + 1.去官网下载安装包 + 2.运行安装包 + 3.安装向导步骤(一路点下一步即可) + 4.验证是否安装成功 + 5. 最简单测试:运行一段 Node.js \ No newline at end of file diff --git "a/\345\205\250\344\277\212\346\236\227/20260309-npm\344\270\216\345\214\205\347\256\241\347\220\206.md" "b/\345\205\250\344\277\212\346\236\227/20260309-npm\344\270\216\345\214\205\347\256\241\347\220\206.md" new file mode 100644 index 0000000000000000000000000000000000000000..efa6bb64fc708f32b8703efee5c111ee0c585f38 --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20260309-npm\344\270\216\345\214\205\347\256\241\347\220\206.md" @@ -0,0 +1,65 @@ +### 选择题 +1.package.json中,哪个字段用于记录项目运行必需的依赖? + + 答:dependencies +2.版本号"^4.18.0"表示安装什么版本 + + 答: 安装4.x.x最新版本 +3.下面哪个命令可以查看npm的镜像源设置? + + 答:npm config get registry +4.安装全局包的参数是? + + 答:--global +5.npm install 和 npm ci 有什么区别? + + 答:npm ci更快,适合CI/CD环境 +6.npm install 和 npm ci 有什么区别? + + 答:支持离线安装 +7.pnpm的主要特点是什么? + + 答:节省磁盘空间 +## 简答题 +1.请解释dependencies和devDependencies的区别。 + + 答:dependencies 是项目运行必需的生产依赖,随项目发布;devDependencies 仅开发阶段使用,发布时会被忽略。 +2.什么是语义化版本号?请举例说明 "^1.2.3" 的含义 + + 答:语义化版本号是一套标准化的版本命名规则,目的是让开发者通过版本号就能清晰判断更新的类型和兼容性,格式为 MAJOR.MINOR.PATCH(主版本号。次版本号。补丁版本号),每个部分都是非负整数,且不包含前导零。 + + ^1.2.3:主版本为1.x.x 包含1.2.3以及1.2.4等 +3.为什么国内使用npm需要配置镜像源? + + 答:服务器在国外,国内网络访问: + 1.速度慢 + 2.丢包、超时 + 3.安装大型依赖(如 node-sass、electron)经常失败 +4.请描述npm install命令的执行过程。 + + 答: + 1. 读取配置与环境 + 2. 解析依赖声明 + 3. 检查缓存与 lock 文件 + 4. 构建依赖树(最重要的一步) + 5. 下载依赖包 + 6. 解压并安装到 node_modules + 7. 执行生命周期脚本(可选) + 8. 更新 lock 文件与 package.json +5.全局安装和本地安装有什么区别? + + 答: + 全局安装:装在系统目录,供所有项目使用终端命令,不写入项目依赖,有版本冲突风险; + + 本地安装:装在项目 node_modules,仅当前项目使用,可代码引入 / 通过 npm scripts 调用,版本独立无冲突; +6.yarn和npm相比有什么优势? + + 答:Yarn 核心优势是安装速度更快、离线模式更友好、锁文件更可靠、Monorepo 支持更好; +7.pnpm的node_modules结构有什么特点?为什么能节省空间? + + 答: + pnpm 的 node_modules 核心是符号链接 + 全局内容可寻址存储,顶层仅存直接依赖,子依赖嵌套且通过链接指向全局 store; + + 节省空间的关键是跨项目 / 同项目共享依赖副本,用链接替代复制,同一个版本的包全局仅存一份; + + 相比 npm/yarn,pnpm 不仅大幅节省磁盘空间,还能避免隐式依赖,安装速度也更快。 diff --git "a/\345\205\250\344\277\212\346\236\227/20260311-\346\250\241\345\235\227\346\223\215\344\275\234.md" "b/\345\205\250\344\277\212\346\236\227/20260311-\346\250\241\345\235\227\346\223\215\344\275\234.md" new file mode 100644 index 0000000000000000000000000000000000000000..438065044e5116662aa7479fce28af4667099869 --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20260311-\346\250\241\345\235\227\346\223\215\344\275\234.md" @@ -0,0 +1,48 @@ +## 练习 +### 选择题 +1. + + 在CommonJS模块系统中,引入模块使用 require +2. + + 正确的CommonJS导出方式: module.exports = ... +3. + + ES Modules需要设置 "type": "module"才能在Node.js中使用 +4. + + exports = function() { console.log('hello'); }; + 应该是 module.exports +5. + + 模块化的好处 + 1. 代码复用 + 2. 便于维护 + 3. 清晰结构 + +### 简答题 +1.什么是模块?为什么要使用模块? + + 模块 = 把一段相对独立、可复用的代码,单独放在一个文件里,方便其他地方导入使用。 + 为了复用、清晰、好维护、少出错、效率高。 +2.请解释module.exports和exports的区别。 + + 本质关系:exports 是 module.exports 的引用(别名),初始指向同一个空对象。 +导出规则:Node.js 最终导出的是 module.exports,而非 exports。 +使用区别:给 exports 加属性和 module.exports 等价;直接给 exports 赋值会失效,必须用 module.exports 赋值。 +3.CommonJS和ES Modules有什么区别? + + 语法层面:CJS 用 require/module.exports,ESM 用 import/export; +核心逻辑:CJS 运行时动态加载(同步),ESM 编译时静态加载(异步),后者支持树摇; +环境适配:CJS 是 Node.js 老规范,ESM 是官方新标准,前端优先用 ESM。 +4.Node.js加载模块的顺序是怎样的? + + + 1.缓存优先:任何模块加载先查缓存,避免重复加载; + 2.优先级排序:核心模块 > 文件模块(路径开头) > 第三方模块(无路径); + 3.查找规则:文件模块按「文件→文件夹入口」查找,第三方模块递归向上找 node_modules。 +5.什么是模块作用域?它有什么作用? + + 1.模块作用域定义:每个 Node.js 模块有独立作用域,内部变量 / 函数默认私有,仅模块内可访问; + 2.核心作用:① 避免全局变量污染和命名冲突;② 封装内部逻辑,提高代码安全性;③ 明确模块边界,提升可维护性; + 3.关键规则:只有通过 module.exports/exports 导出的内容,才能被其他模块通过 require 访问。 \ No newline at end of file diff --git "a/\345\205\250\344\277\212\346\236\227/20260313-\347\273\274\345\220\210.md" "b/\345\205\250\344\277\212\346\236\227/20260313-\347\273\274\345\220\210.md" new file mode 100644 index 0000000000000000000000000000000000000000..9a526761cf4f72701b7a9146caaa78fbc16ed381 --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20260313-\347\273\274\345\220\210.md" @@ -0,0 +1,79 @@ +## 笔记 + +|知识点 |关键内容| +|--|--| +|文件操作| fs模块读写文件| +|路径处理| path模块处理文件路径| +|命令解析| switch或commander解析命令| +|数据存储| JSON文件持久化数据| + +## 完整命令 + + + node todo.js add <内容> # 添加待办 + node todo.js list # 列出待办 + node todo.js done <编号> # 标记完成 + node todo.js delete <编号> # 删除待办 + node todo.js clear # 清空待办 + node todo.js help # 显示帮助 + +## 作业 + +1. + + Node.js中,获取命令行参数的属性是process.argv + +2. + + fs.readFile可以读取文件内容 + +3. + + __dirname当前文件所在目录 + +4. + + package.json中bin用于配置全局命令 + +5. + + 图形界面更美观是命令行工具的优点 + +6. + +## 简答题 +1.请解释什么是CLI工具?它和GUI有什么区别 + + CLI工具是“指令驱动”的轻量交互工具,侧重高效、自动化和资源节省;GUI是“图形驱动”的直观交互工具,侧重易用性和可视化。二者没有优劣之分,根据使用场景和需求选择即可——普通用户日常使用优先GUI,专业场景(开发、运维)优先CLI。 +2.process.argv返回的数组包含哪些内容? + + 索引值 + +3.请说明fs.readFileSync和fs.readFile的区别 + + fs.readFile:异步读取。调用后不会阻塞后续代码执行,文件读取完成后,通过回调函数(或Promise)返回结果。Node.js 的核心特性就是异步非阻塞,该方法更符合 Node.js 设计理念。 + + fs.readFileSync:同步读取。调用后会阻塞后续代码执行,直到文件读取完成、返回结果后,才会继续执行下一行代码。 + +4.为什么要使用JSON文件存储数据?有什么优缺点? + + 原因:选择JSON存储数据,核心是其简洁性和跨环境兼容性 + + 优点: + 1.轻量高效 + 2.易维护 + 3.通用性强 + 4.适合存储结构化数据 + 缺点: + 1.不支持注释 + 2.不适合存储大量二进制数据 + 3. 解析性能有限 + 4.无类型约束 + 5.不支持并发写入:多个程序同时读写同一个JSON文件时,容易出现数据错乱, + +5.如何让开发的CLI工具可以全局使用 + + 1.编写 CLI 核心代码 + 2.配置 package.json + 3.全局链接(开发阶段) + 4.发布到 npm 后,用户可通过 npm install -g my-global-cli 全局安装; \ No newline at end of file diff --git "a/\345\205\250\344\277\212\346\236\227/20260316-\345\206\205\347\275\256\346\250\241\345\235\227.md" "b/\345\205\250\344\277\212\346\236\227/20260316-\345\206\205\347\275\256\346\250\241\345\235\227.md" new file mode 100644 index 0000000000000000000000000000000000000000..a23d356cba6bc7f7ee0db30be6b7d98bf5483ee7 --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20260316-\345\206\205\347\275\256\346\250\241\345\235\227.md" @@ -0,0 +1,208 @@ +## 内置模块 +### 笔记 +### 内置模块的特点 +|特点| 说明| +|---|---| +|无需安装 |Node.js自带,直接 require 即可| +|性能优化 |由C/C++编写,执行效率高| +|功能强大 |涵盖文件、网络、加密等方方面面| +|稳定可靠 |经过长期测试,稳定可用| + +### 选择题 +1 + + process.version可以获取Node.js的版本号 +2 + + Buffer.alloc(10)创建的Buffer,长度是10字节 +3. + + "你好"的Buffer长度6字节(通常汉字在utf-8编码中一个汉字占三个字节) +4. + + _dirname表示当前文件所在目录 +5. + + console.time()和console.timeEnd()的作用是计时 +### 简答题 +1.解释console.log和console.error的区别 + + 核心差异:console.log 输出到 stdout(普通信息),console.error 输出到 stderr(错误信息),且后者在终端通常显红色,更醒目。 + 使用原则:正常流程 / 调试信息用 console.log,异常 / 错误提示用 console.error,便于日志分类、排查问题。 + 扩展价值:区分两者可实现日志的精细化管理(如单独收集错误日志),提升问题定位效率。 +2.process.argv返回的数组包含哪些内容?请举例说明。 + + process.argv 数组核心包含三部分:Node 可执行文件路径(第 0 位)、当前文件路径(第 1 位)、自定义命令行参数(第 2 位及以后)。 + 自定义参数需从 process.argv.slice(2) 中获取,是处理命令行输入的核心数据来源。 + 数组元素顺序严格对应命令行输入顺序,含空格的参数需用引号包裹。 +3.Buffer和普通数组有什么区别? + + 核心差异:普通数组存储任意 JS 类型、动态长度、基于 V8 堆内存;Buffer 仅存字节数据、固定长度、基于堆外内存,专为二进制处理设计。 + 使用原则:业务数据处理用普通数组,文件 / 网络等二进制数据处理用 Buffer。 + 关键特性:Buffer 支持编码转换、内存更高效,是 Node.js 处理 IO 操作的核心工具。 +4.__dirname和process.cwd()有什么区别? + + 核心区别:__dirname 是文件所在目录的绝对路径(固定不变),process.cwd() 是执行 node 命令的目录(随执行位置变化)。 + 使用原则:读取文件自身关联的资源用 __dirname,处理用户命令相关的路径用 process.cwd()。 + 关键记忆:__dirname 跟 “文件走”,process.cwd() 跟 “命令走”。 +5.path.join()和path.resolve()有什么区别? + + 核心区别:path.join() 仅拼接 + 规范化路径片段(可返回相对路径),path.resolve() 解析为绝对路径(模拟 cd 逻辑,遇绝对路径终止向左解析)。 + 使用原则:需要相对路径 / 拼接文件关联路径用 path.join(),需要绝对路径 / 基于工作目录解析路径用 path.resolve()。 + 关键记忆:join 是 “拼接”,resolve 是 “解析(为绝对路径)”。 + +### 操作题 +``` +// 第一题 关键 process.env || process.env 是 Node.js 全局对象 process 的属性,自动获取当前操作系统的所有环境变量 +// import process from 'process' + +// function myPath(){ +// const env=process.env; +// console.log(env); +// } +// myPath(); + +//第二题 +import fs from 'fs' +import { exit } from 'process'; +// process.argv[2] 是操作类型(add/sub/mul) +let math = process.argv[2]; +let num1 = Number(process.argv[3]) +let num2 = Number(process.argv[4]) +//判断是否为数字 ([3][4]默认是字符串,需要Number()转换成数字 +if (isNaN(num1) || isNaN(num2)) { + console.log('请输入有效的数字!'); + process.exit(); +} +let result; +if (math === 'add') { + result = num1 + num2; +} else if (math === 'sub') { + result = num1 - num2; +} else if (math === 'mul') { + result = num1 * num2; +} else { + console.log('不支持该操作!'); + process.exit(); + +} +console.log(result); + +//第三题 Buffer操作:创建一个程序,将中文字符串转为Buffer,再转回字符串,验证是否一致。 + + +// 1. 定义要测试的中文字符串 +const str = '你好,Node.js!测试中文转Buffer'; + +// 2. 转Buffer(指定UTF-8编码,中文必须指定) +const buf = Buffer.from(str, 'utf8'); + +// 3. Buffer转回字符串 +const newStr = buf.toString('utf8'); + +// 4. 验证并输出结果 +console.log('原始字符串:', str); +console.log('转回字符串:', newStr); +console.log('是否一致:', str === newStr ? '✅ 一致' : '❌ 不一致'); + +//第四题 创建一个程序,接收文件路径,输出文件名、扩展名、所在目录。 +//引入node.js 内置的path模块(处理路径专用) +const path = require('path'); +//获取命令行传入的文件路径参数 +const filepath = process.argv[2]; + +if (!filepath) { + console.error('用法:node path-parser.js [文件路径]'); + console.error('示例:node path-parser.js ./test.txt 或 node path-parser.js /user/doc/test.png'); + process.exit(1); +} + +//解析路径:提取目录 文件名 扩展名 +const parsedPath = path.parse(filepath); +// 整理输出信息(兼容无扩展名的文件) +const dir = parsedPath.dir; // 所在目录 +const fileName = parsedPath.name; // 文件名(不含扩展名) +const ext = parsedPath.ext || '无扩展名'; // 扩展名(无则显示“无扩展名”) + +// 格式化输出结果 +console.log('=== 文件路径解析结果 ==='); +console.log('输入路径:', filePath); +console.log('所在目录:', dir); +console.log('文件名(不含扩展名):', fileName); +console.log('扩展名:', ext); + +//第五题 + +import fs from 'fs' + +let command = process.argv[2]; +let params = process.argv[3]; + + +if (command == 'list') { + console.log('========待办事项'); + let list = readFile(); + console.log(list) + +} else if (command == 'add') { + console.log('添加成功'); + let arr = readFile(); + console.log({ 'acting': params, 'isdone': false }) + arr.push({ 'acting': params, 'isdone': false }) + writeFile(arr); + let newArr = readFile(); + +} else if (command == 'mark') { + console.log('状态切换并完成'); + let fix=readFile(); + fix.forEach((item)=>{ + if(item.acting === params){ + if(item.isdone){ + item.isdone=false; + }else{ + item.isdone=true; + } + /*法2*/ + // item.isdone = !item.isdone + } + }) + // let fixdata=JSON.stringify(fix); + // fs.writeFileSync('./todo.json',fixdata,"utf-8"); + // console.log(fix); + writeFile(fix) + + +} else if (command == 'del') { + console.log('删除成功'); + let dell = parseInt(params); + let delArr = readFile(); + delArr.splice(dell - 1, 1); + writeFile(delArr); + +} else if (command == 'clear') { + console.log('清除成功'); + writeFile([]); +} else { + console.log('未知命令,请重新输入'); +} + +function readFile(filePath) { + filePath = filePath || './todo.json'; + if (fs.existsSync(filePath)) { + let data = fs.readFileSync(filePath, 'utf-8'); + try { + JSON.parse(data)/*转换为JS可操作类型*/ + } catch (error) { + fs.writeFileSync(filePath, "[]", "utf-8") + } + data = fs.readFileSync(filePath, 'utf-8'); + return JSON.parse(data) || []; + } + return []; +} +function writeFile(fileContent, filePath) { + filePath = filePath || './todo.json'; + let jsonString = JSON.stringify(fileContent); + fs.writeFileSync(filePath, jsonString,); +} +``` \ No newline at end of file diff --git "a/\345\205\250\344\277\212\346\236\227/20260318-\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227\345\211\257\346\234\254.md" "b/\345\205\250\344\277\212\346\236\227/20260318-\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227\345\211\257\346\234\254.md" new file mode 100644 index 0000000000000000000000000000000000000000..12926474e800cc27f51a8d163b39466f090c744b --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20260318-\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227\345\211\257\346\234\254.md" @@ -0,0 +1,97 @@ +# 笔记 +## 一、模块核心认知 +### 1. 学习价值 +Web 应用中文件操作的核心场景: +用户文件上传(头像 / 附件)、配置文件读取 +日志生成、数据备份 +Node.js 通过fs模块提供完整的文件操作能力 +### 2. 核心特点 +功能全覆盖:读写、复制、删除、移动、监听等 +两种操作模式:同步(方法名带Sync)/ 异步(回调 / Promise) +支持大文件:流式处理、权限控制 +## 二、核心 API 分类及用法 +### 1. 文件读写(核心) +操作类型 同步方法 异步回调方法 Promise 方法(推荐) +读取文件 fs.readFileSync(path, 'utf8') fs.readFile(path, 'utf8', (err, data) => {}) fs.promises.readFile(path, 'utf8') +写入文件 fs.writeFileSync(path, data) fs.writeFile(path, data, (err) => {}) fs.promises.writeFile(path, data) +追加写入 fs.appendFileSync(path, data) fs.appendFile(path, data, (err) => {}) fs.promises.appendFile(path, data) +关键说明: +读取二进制文件(图片 / 视频)时,无需指定编码,返回Buffer对象 +Promise 方式需结合async/await使用,错误通过try/catch捕获 +### 2. 文件基础操作 +操作 核心方法 说明 +检查存在性 fs.existsSync(path) 返回布尔值 +获取文件信息 fs.statSync(path) 可判断文件 / 目录、获取大小 / 时间 +删除文件 fs.unlinkSync(path) / fs.promises.unlink(path) 同步 / 异步删除文件 +重命名 / 移动 fs.renameSync(oldPath, newPath) 跨目录重命名即文件移动 +复制文件 fs.copyFileSync(src, dest) Node.js 14 + 内置,也可通过流实现 +### 3. 目录操作 +操作 核心方法 关键参数 / 说明 +创建目录 fs.mkdirSync(path, { recursive: true }) recursive: true支持多级创建 +读取目录 fs.readdirSync(path, { withFileTypes: true }) 可区分文件 / 目录 +删除目录 fs.rmSync(path, { recursive: true, force: true }) Node.js 16+,递归删除非空目录 +### 4. 文件监听 +// 监听文件变化(轻量) +fs.watch('./data.txt', (eventType, filename) => { + console.log(`文件${filename}发生${eventType}事件`); +}); + +// 监听文件详细变化(精度更高) +fs.watchFile('./data.txt', (curr, prev) => { + console.log('修改时间:', curr.mtime); +}); +## 三、实战案例(核心代码) +### 1. 文件复制工具 +const fs = require('fs'); +const path = require('path'); + +function copyFile(src, dest) { + if (!fs.existsSync(src)) return console.error('源文件不存在'); + // 确保目标目录存在 + fs.mkdirSync(path.dirname(dest), { recursive: true }); + fs.copyFileSync(src, dest); +} +### 2. 目录备份工具(带时间戳) +class BackupTool { + constructor(sourceDir, backupDir) { + this.sourceDir = sourceDir; + this.backupDir = backupDir; + } + + backup() { + // 创建带时间戳的备份目录 + const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); + const targetDir = path.join(this.backupDir, `backup_${timestamp}`); + fs.mkdirSync(targetDir, { recursive: true }); + + // 遍历复制文件 + fs.readdirSync(this.sourceDir, { withFileTypes: true }).forEach(item => { + const src = path.join(this.sourceDir, item.name); + if (item.isFile()) fs.copyFileSync(src, path.join(targetDir, item.name)); + }); + } +} +### 3. 递归目录浏览器(带文件大小格式化) +function browseDir(dirPath, indent = 0) { + const items = fs.readdirSync(dirPath, { withFileTypes: true }); + const prefix = ' '.repeat(indent); + + items.forEach(item => { + const fullPath = path.join(dirPath, item.name); + if (item.isDirectory()) { + console.log(`${prefix}📁 ${item.name}/`); + browseDir(fullPath, indent + 1); // 递归子目录 + } else { + const size = fs.statSync(fullPath).size; + console.log(`${prefix}📄 ${item.name} (${formatSize(size)})`); + } + }); +} + +// 格式化文件大小(B/KB/MB/GB) +function formatSize(bytes) { + const k = 1024; + const sizes = ['B', 'KB', 'MB', 'GB']; + const i = Math.floor(Math.log(bytes) / Math.log(k)) || 0; + return (bytes / Math.pow(k, i)).toFixed(2) + ' ' + sizes[i]; +} \ No newline at end of file diff --git "a/\345\205\250\344\277\212\346\236\227/20260319-\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227.md" "b/\345\205\250\344\277\212\346\236\227/20260319-\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227.md" new file mode 100644 index 0000000000000000000000000000000000000000..190bd8d034d4dced72c7b4919cd6b11ff3685776 --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20260319-\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227.md" @@ -0,0 +1,111 @@ +## 简单文件浏览器 +## 笔记 + + 步骤: + 1.先把需要的包导入进去 + 2.拿到参数 + 3.调用函数判断路径是否存在 + 4.获取命令参数 + + + +## 作业 +### 选择题 + + 1.fs.existsSync()可以检查文件是否存在 + 2. 使用fs.writeFileSync()写入文件 + 3.appendFileSync是追加,writeFileSync是覆盖 + 4.fs.mkdirSync('./a/b/c', { recursive: true })创建多级目录 + 5. fs.statSync()可以获取文件的详细信息(大小、时间等) + +### 简答题 + + 1.同步方法和异步方法的区别 + 核心区别:同步阻塞线程(等操作完成再执行),异步非阻塞(后台执行、回调通知); + 写法差异:同步代码线性直观,异步需用回调 / Promise/async-await; + 场景选择:简单脚本用同步,高并发服务用异步。 + + 2.fs.readFile和fs.readFileSync有什么区别? + 执行模式:fs.readFile 异步非阻塞(后台执行,回调通知),fs.readFileSync 同步阻塞(等完成再执行); + 错误 / 结果:同步用 try/catch 捕获错误、直接返回结果;异步通过回调参数获取错误 / 结果; + 场景选择:简单脚本用同步,高并发服务用异步。 + + 3.如何实现文件的追加写入? + 首先先确保包的引入 + 然后使用fs.appendFileSync() + + 4.什么是流式处理?它适合什么场景? + 核心定义:流式处理是将数据拆分为小块,分批次、非阻塞地读取 / 写入 / 处理,内存占用极低; + 核心优势:处理大文件 / 持续数据时,避免内存溢出,提升程序稳定性和性能; + 适用场景:大文件读写、实时数据传输、边读边处理的转换场景、高并发服务端接口;小文件 / 需完整数据处理的场景不适合。 + + 5.如何监听文件的变化? + 原生首选:fs.watch 性能高,适合大多数场景;fs.watchFile 兼容性好但性能稍差; + 生产环境:优先用 chokidar,解决跨平台差异,API 更友好; + 关键技巧:监听文件修改时加 try/catch 处理错误,频繁触发时加防抖逻辑。 + +### 操作 +``` +//同步读取 +// const fs = require('fs') + +// const content =fs.readFileSync('./test.txt','utf-8') + +// console.log(content); + +//异步读取 +// fs.readFile('./work.txt','utf-8',(err,work)=>{ +// if(err){ +// console.error('读取失败:',err); +// return; +// } +// console.log('读取内容',work); + +// }); + +//同步写入(这里的writeFileSync会覆盖文件的内容) +// const fs = require('fs'); +// fs.writeFileSync('./work.txt', 'hello,帅气的小灰灰') +//追加写入(不会覆盖原文件的内容) +// fs.appendFileSync('./work.txt', '为什么小灰灰这么帅/n'); + + +//异步写入 +// const fs = require('fs'); + +// fs.writeFile('./work.txt','我不是小灰灰','utf-8',(err)=>{ +// if(err)throw err; +// console.log('写入成功'); + +// }); +//异步追加 +// fs.appendFile('./work.txt','骗你的我是小灰灰\n',(err=>{ +// if(err)throw err; +// console.log('追加成功'); + +// })); + +//实现一个函数,递归复制整个目录(要点:读取目录 拼路径 文件夹递归调用自己 +// const fs = require('fs'); +// const path = require('path'); +// function scan(dir) { +// try { +// fs.readdirSync(dir).forEach(file => { +// const fullPath = path.join(dir, file); +// console.log(fullPath); + +// if (fs.statSync(fullPath).isDirectory()) { +// scan(fullPath); +// } + +// }); +// } catch (err) { + +// } +// } +// scan('./') +//try catch的作用遇到不能访问的目录自动跳过 + +//文件搜索 + +``` \ No newline at end of file diff --git "a/\345\205\250\344\277\212\346\236\227/20260320-http\346\250\241\345\235\227.md" "b/\345\205\250\344\277\212\346\236\227/20260320-http\346\250\241\345\235\227.md" new file mode 100644 index 0000000000000000000000000000000000000000..36155f043698bf1f56bb138b06a553bc12aeb658 --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20260320-http\346\250\241\345\235\227.md" @@ -0,0 +1,73 @@ +## http模块 +### 笔记 +|作用 |说明| +|---|---| +|创建服务器 |使用http.createServer()| +|发送请求 |使用http.request()| +|处理请求 |获取URL、Method、参数等| +|返回响应 |发送HTML、JSON、图片等| + +### 核心知识点 +|识点 |关键内容| +|---|---| +|创建服务器 |http.createServer()| +|请求对象 |req.method / req.url / req.headers| +|URL解析 |new URL() / searchParams| +|客户端 |http.get() / http.request()| + +创建一个HTTP服务器需要使用哪个模块?(B) +A. url +B. http +C. fs +D. path + +获取请求的方法(GET、POST)应该访问哪个属性?(B) +A. req.url +B. req.method +C. req.headers +D. req.body + +设置响应状态码使用哪个属性?(B) +A. res.status +B. res.statusCode +C. res.code +D. res.statusNumber + +返回JSON数据需要设置什么响应头?(B) +A. 'Content-Type': 'text/html' +B. 'Content-Type': 'application/json' +C. 'Content-Type': 'text/plain' +D. 'Content-Type': 'application/xml' + +使用哪个方法发送响应?(C) +A. res.send() +B. res.write() +C. res.end() +D. res.close() + +### 简答题 +请解释req和res分别代表什么? +req:别人发给我的东西(请求) +res:我要返回给别人的东西(响应) + + +http.createServer的回调函数接收哪些参数? +http.createServer() 的回调函数固定接收 req(请求对象)和 res(响应对象)两个参数; +req 用于读取客户端的请求信息,res 用于向客户端返回响应数据; +回调函数每次接收到新请求时触发,且必须通过 res.end() 结束响应。 + + +如何获取URL中的查询参数? +用 new URL(req.url, '基准地址') +再用 .searchParams.get('参数名') 获取查询参数 + + +res.writeHead和res.setHeader有什么区别? +etHeader = 攒响应头 +writeHead = 发响应头 + 状态码 + + +http.get和http.request有什么区别? +仅需发送 GET 请求 → 优先用 http.get(),代码更简洁,无需手动调用 end(); +需发送 POST/PUT/DELETE 等请求,或需要自定义请求头、请求体 → 必须用 http.request(); +http.get() 是 http.request() 的 GET 专用封装,核心逻辑完全依赖后者。 \ No newline at end of file