From 9b09fa49745614615d2743d9ed124ad3d85dc2ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B7=BC=E6=9E=97?= <3330918054@qq.com> Date: Thu, 19 Mar 2026 16:58:17 +0800 Subject: [PATCH 1/4] biji --- .../20260316-\347\273\203\344\271\240.md" | 0 ...05\347\275\256\346\250\241\345\235\227.md" | 82 +++++++++ ...73\347\273\237\346\250\241\345\235\227.md" | 167 ++++++++++++++++++ 3 files changed, 249 insertions(+) create mode 100644 "\351\273\204\346\267\274\346\236\227/20260316-\347\273\203\344\271\240.md" create mode 100644 "\351\273\204\346\267\274\346\236\227/20260318-\345\237\272\346\234\254\345\206\205\347\275\256\346\250\241\345\235\227.md" create mode 100644 "\351\273\204\346\267\274\346\236\227/20260319-\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227.md" diff --git "a/\351\273\204\346\267\274\346\236\227/20260316-\347\273\203\344\271\240.md" "b/\351\273\204\346\267\274\346\236\227/20260316-\347\273\203\344\271\240.md" new file mode 100644 index 0000000..e69de29 diff --git "a/\351\273\204\346\267\274\346\236\227/20260318-\345\237\272\346\234\254\345\206\205\347\275\256\346\250\241\345\235\227.md" "b/\351\273\204\346\267\274\346\236\227/20260318-\345\237\272\346\234\254\345\206\205\347\275\256\346\250\241\345\235\227.md" new file mode 100644 index 0000000..93366c0 --- /dev/null +++ "b/\351\273\204\346\267\274\346\236\227/20260318-\345\237\272\346\234\254\345\206\205\347\275\256\346\250\241\345\235\227.md" @@ -0,0 +1,82 @@ +## 基本内置模块笔记 + + 1. console模块 - 多种输出方式 + + ```js +//基本输出方式 +console.log('普通信息'); +console.info('提示信息'); +console.warn('警告信息'); +console.error('错误信息'); +console.table([{name: '张三', age: 20}]); + +//格式化输出 +// %s 字符串 +console.log('%s 今天学习了 %d 小时', '小明', 2); + +// %d 数字 +console.log('进度: %d%%', 75); + +// %j JSON +console.log('%j', {name: '张三', age: 20}); +``` + + 2. process模块 - 获取进程信息 + + ```js + //进程信息 +console.log('Node版本:', process.version); +console.log('平台:', process.platform); +console.log('当前目录:', process.cwd()); + + //环境变量 +console.log(process.env) +``` + 3. Buffer模块 - 处理二进制 + +**Buffer用于处理二进制数据,例如:** + +- 文件读写 +- 网络传输 +- 图片处理 +- 加密解密 + + ```js +const buf = Buffer.from('Hello'); +console.log(buf); +``` + 4. path模块 - 路径处理 + + ```js +const path = require('path'); +console.log(__dirname); +console.log(__filename); +``` + +## 练习 +### 简单题 +1.请解释console.log和console.error的区别。 + +2.process.argv返回的数组包含哪些内容?请举例说明。 + +3.Buffer和普通数组有什么区别? + +4.__dirname和process.cwd()有什么区别? + +5.path.join()和path.resolve()有什么区别? + +### 操作题 +1.信息展示:创建一个程序,输出当前系统的所有环境变量。 + +2.参数解析:创建一个计算器程序,支持: + +node calc.js add 5 3 → 输出 8 +node calc.js sub 5 3 → 输出 2 +node calc.js mul 5 3 → 输出 15 + + +3.Buffer操作:创建一个程序,将中文字符串转为Buffer,再转回字符串,验证是否一致。 + +4.路径处理:创建一个程序,接收文件路径,输出文件名、扩展名、所在目录。 + +5.综合应用:创建一个CLI工具,接受命令行参数,实现简单的待办列表功能(添加、列出、删除)。 \ No newline at end of file diff --git "a/\351\273\204\346\267\274\346\236\227/20260319-\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227.md" "b/\351\273\204\346\267\274\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 0000000..487adcf --- /dev/null +++ "b/\351\273\204\346\267\274\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,167 @@ +## 文件系统模块笔记 +**fs模块的特点** + +| 特点 | 说明 | +|-------- |-------------| +| 功能完善 | 读写、复制、删除、移动、监听... | +| 两种方式 | 同步(带Sync)和异步(回调/Promise) | +| 流式处理 | 支持大文件流式读写 | +| 权限控制 | 支持设置文件权限 | + +1.效果展示 +```js +const fs = require('fs'); +const path = require('path'); + +// 1. 读取文件 + +//同步读取 +const content = fs.readFileSync('./data.txt', 'utf8'); +console.log(content); + +//异步读取(回调方式) +fs.readFile('./data.txt', 'utf8', (err, data) => { + if (err) { + console.error('读取失败:', err); + return; + } + console.log('文件内容:', data); +}); + +// 异步读取(Promise) +async function readFile() { + try { + const content = await fs.readFile('./data.txt', 'utf8'); + console.log(content); + } catch (err) { + console.error('读取失败:', err); + } +} +readFile(); + + +// 2. 写入文件 + +//同步写入 +fs.writeFileSync('./new.txt', 'Hello Node.js'); +//异步写入 +fs.writeFile('./data.txt', 'Hello World', 'utf8', (err) => { + if (err) throw err; + console.log('写入成功'); +}); + + +// 3. 判断文件是否存在 +if (fs.existsSync('./data.txt')) { + console.log('文件存在'); +} + +// 4. 读取目录 +const files = fs.readdirSync('./src'); +console.log(files); + +// 5. 创建目录 +fs.mkdirSync('./backup', { recursive: true }); +``` + +2.文件操作 +- 检查文件状态 +```js +const fs = require('fs'); + +// 检查文件/目录是否存在 +fs.existsSync('./data.txt'); // true 或 false + +// 获取文件状态 +const stats = fs.statSync('./data.txt'); +console.log('是文件:', stats.isFile()); +console.log('是目录:', stats.isDirectory()); +console.log('文件大小:', stats.size, '字节'); +console.log('创建时间:', stats.birthtime); +console.log('修改时间:', stats.mtime); + +// 异步版本 +fs.stat('./data.txt', (err, stats) => { + console.log('大小:', stats.size); +}); +``` +- 删除文件 +```js +const fs = require('fs'); + +// 删除文件(同步) +fs.unlinkSync('./temp.txt'); + +// 删除文件(异步) +fs.unlink('./temp.txt', (err) => { + if (err) throw err; + console.log('删除成功'); +}); +``` + +- 复制文件 +```js +const fs = require('fs'); + +// 复制文件 +function copyFile(src, dest) { + const data = fs.readFileSync(src); + fs.writeFileSync(dest, data); +} +copyFile('./source.txt', './dest.txt'); +``` + +3.目录操作 +- 创建目录 +```js +const fs = require('fs'); + +// 创建单个目录(同步) +fs.mkdirSync('./backup'); + +// 创建多级目录(同步) +fs.mkdirSync('./backup/data/images', { recursive: true }); +``` + +- 读取目录 +```js +const fs = require('fs'); + +// 读取目录内容(同步) +const files = fs.readdirSync('./src'); +console.log(files); // ['index.js', 'utils.js', 'data'] +``` + +- 删除目录 +```js +const fs = require('fs'); + +// 删除空目录(同步) +fs.rmdirSync('./empty-dir'); + +// 删除目录及内容(同步,Node.js 16+) +fs.rmSync('./backup', { recursive: true, force: true }); +``` + +## 练习 +### 简答题 +请解释同步方法和异步方法的区别。 + +fs.readFile和fs.readFileSync有什么区别? + +如何实现文件的追加写入? + +什么是流式处理?它适合什么场景? + +如何监听文件的变化? + +### 操作题 +文件读取器:创建一个程序,读取指定文件的内容并输出到控制台。 + +文件写入器:创建一个程序,接收命令行输入的内容,写入到文件中。 + +目录复制:实现一个函数,递归复制整个目录。 + +文件搜索:创建一个文件搜索工具,查找指定目录下所有特定类型的文件(如.js文件)。 + +日志系统:创建一个简单的日志系统,支持写入日志到文件,包含时间戳和日志级别。 \ No newline at end of file -- Gitee From 590eb41c76c4f0b95ae57494d5ebce474e6092c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B7=BC=E6=9E=97?= <3330918054@qq.com> Date: Thu, 19 Mar 2026 17:27:58 +0800 Subject: [PATCH 2/4] lianx --- ...05\347\275\256\346\250\241\345\235\227.md" | 88 ++++++++++++++++++- ...73\347\273\237\346\250\241\345\235\227.md" | 20 ++--- 2 files changed, 97 insertions(+), 11 deletions(-) diff --git "a/\351\273\204\346\267\274\346\236\227/20260318-\345\237\272\346\234\254\345\206\205\347\275\256\346\250\241\345\235\227.md" "b/\351\273\204\346\267\274\346\236\227/20260318-\345\237\272\346\234\254\345\206\205\347\275\256\346\250\241\345\235\227.md" index 93366c0..c997ba3 100644 --- "a/\351\273\204\346\267\274\346\236\227/20260318-\345\237\272\346\234\254\345\206\205\347\275\256\346\250\241\345\235\227.md" +++ "b/\351\273\204\346\267\274\346\236\227/20260318-\345\237\272\346\234\254\345\206\205\347\275\256\346\250\241\345\235\227.md" @@ -57,26 +57,112 @@ console.log(__filename); ### 简单题 1.请解释console.log和console.error的区别。 +- 核心用途:console.log 用于输出普通、正常的运行信息(如调试日志、执行结果);console.error 专门用于输出错误、异常信息(如参数错误、程序执行失败)。 + +- 输出流:console.log 写入标准输出流(stdout),console.error 写入标准错误流(stderr),可分别重定向(如 node app.js > log.txt 只保存 log,node app.js 2> err.txt 只保存 error)。 + +- 视觉表现:终端中 console.error 输出通常为红色,更醒目;console.log 为默认颜色。 + 2.process.argv返回的数组包含哪些内容?请举例说明。 +process.argv 是 Node.js 返回命令行参数的数组,内容固定分为三部分: + +- 索引 0:Node.js 可执行文件的绝对路径(如 /usr/local/bin/node 或 C:\nodejs\node.exe); +- 索引 1:当前执行的脚本文件的路径(如 /Users/test/calc.js); +- 索引 2 及以后:用户输入的命令行参数(按输入顺序排列)。 +- 示例:执行 node calc.js add 5 3 时,process.argv 为 [node路径, calc.js路径, 'add', '5', '3']。 3.Buffer和普通数组有什么区别? +- 存储内容:Buffer 仅存储 0-255 的 8 位无符号整数(二进制数据),普通数组可存储任意 JS 类型(数字、字符串、对象等); +- 长度特性:Buffer 创建后长度固定不可变,普通数组长度可通过 push/pop 等方法动态修改; +- 内存分配:Buffer 分配在 V8 引擎堆外内存,适合处理大二进制数据(如文件、网络流);普通数组分配在 V8 堆内存,适合存储业务数据; +- 功能定位:Buffer 专为二进制数据处理设计,支持编码转换(如 UTF-8/GBK);普通数组无编码概念,仅用于数据存储。 + 4.__dirname和process.cwd()有什么区别? +- 核心含义:__dirname 是当前脚本文件所在目录的绝对路径(以文件物理位置为基准,固定不变);process.cwd() 是 Node.js 进程的当前工作目录(以执行node命令的目录为基准,可变化); +- 可用性:__dirname 仅在 CommonJS 模块中可用,ES 模块需手动实现;process.cwd() 全局可用(CommonJS/ES 模块均支持)。 + 5.path.join()和path.resolve()有什么区别? +- 核心逻辑:path.join() 是将多个路径片段拼接成合法路径(仅做字符串拼接,保留相对路径特征);path.resolve() 是将路径片段解析为绝对路径(从当前工作目录开始,逐层解析,最终返回绝对路径); +- 路径类型:path.join('a', 'b') 返回 a/b(相对路径);path.resolve('a', 'b') 返回 /当前工作目录/a/b(绝对路径); +- 特殊符号处理:path.join 对 ../ 的处理仅作用于拼接的片段(如 join('a', '../b') 返回 b);path.resolve 对 ../ 的处理会向上回溯当前工作目录(如 resolve('a', '../b') 返回 /当前目录/b)。 ### 操作题 1.信息展示:创建一个程序,输出当前系统的所有环境变量。 +```js +console.log('\n=== 环境变量 ==='); +console.log('NODE_ENV:',process.env); +``` 2.参数解析:创建一个计算器程序,支持: node calc.js add 5 3 → 输出 8 node calc.js sub 5 3 → 输出 2 node calc.js mul 5 3 → 输出 15 - +```js +const a = process.argv[2]; +const b = process.argv[3]; +const c = process.argv[4]; +const num1 = Number(b); +const num2 = Number(c); +if(a == "add"){ + console.log(`${num1} + ${num2} = ${num1+num2}`) +}else if(a == "sub"){ + console.log(`${num1} - ${num2} = ${num1-num2}`) +}else if(a == "mul"){ + console.log(`${num1} * ${num2} = ${num1*num2}`) +}else if(a == "div"){ + console.log(`${num1} / ${num2} = ${num1/num2}`) +} +``` 3.Buffer操作:创建一个程序,将中文字符串转为Buffer,再转回字符串,验证是否一致。 +```js +const chineseStr = '将中文字符串转为Buffer'; + +// 1. 字符串转Buffer +const buf = Buffer.from(chineseStr); +console.log('Buffer 内容:', buf); +console.log('Buffer 长度(字节):', buf.length); + +// 2. Buffer转回字符串 +const restoredStr = buf.toString('utf8'); +console.log('转回字符串:', restoredStr); + +// 3. 验证一致性 +if (chineseStr === restoredStr) { + console.log('\n✅ 验证通过:转码前后字符串一致'); +} else { + console.log('\n❌ 验证失败:转码前后字符串不一致'); +} +``` 4.路径处理:创建一个程序,接收文件路径,输出文件名、扩展名、所在目录。 +```js +// path-parser.js +const path = require('path'); +// 获取命令行传入的文件路径 +const inputPath = process.argv[2]; + +// 校验参数 +if (!inputPath) { + console.error('使用方法:node path-parser.js <文件路径>'); + console.error('示例:node path-parser.js /user/doc/test.txt'); + console.error('示例:node path-parser.js C:\\Users\\test\\demo.js'); + process.exit(1); +} + +// 解析路径 +const parsedPath = path.parse(inputPath); + +// 输出解析结果 +console.log('=== 路径解析结果 ==='); +console.log(`完整路径:${inputPath}`); +console.log(`文件名(含扩展名):${parsedPath.base}`); +console.log(`纯文件名(无扩展名):${parsedPath.name}`); +console.log(`扩展名:${parsedPath.ext || '无'}`); +console.log(`所在目录:${parsedPath.dir}`); +``` 5.综合应用:创建一个CLI工具,接受命令行参数,实现简单的待办列表功能(添加、列出、删除)。 \ No newline at end of file diff --git "a/\351\273\204\346\267\274\346\236\227/20260319-\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227.md" "b/\351\273\204\346\267\274\346\236\227/20260319-\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227.md" index 487adcf..548dddf 100644 --- "a/\351\273\204\346\267\274\346\236\227/20260319-\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227.md" +++ "b/\351\273\204\346\267\274\346\236\227/20260319-\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227.md" @@ -145,23 +145,23 @@ fs.rmSync('./backup', { recursive: true, force: true }); ## 练习 ### 简答题 -请解释同步方法和异步方法的区别。 +1.请解释同步方法和异步方法的区别。 -fs.readFile和fs.readFileSync有什么区别? +2.fs.readFile和fs.readFileSync有什么区别? -如何实现文件的追加写入? +3.如何实现文件的追加写入? -什么是流式处理?它适合什么场景? +4.什么是流式处理?它适合什么场景? -如何监听文件的变化? +5.如何监听文件的变化? ### 操作题 -文件读取器:创建一个程序,读取指定文件的内容并输出到控制台。 +1.文件读取器:创建一个程序,读取指定文件的内容并输出到控制台。 -文件写入器:创建一个程序,接收命令行输入的内容,写入到文件中。 +2.文件写入器:创建一个程序,接收命令行输入的内容,写入到文件中。 -目录复制:实现一个函数,递归复制整个目录。 +3.目录复制:实现一个函数,递归复制整个目录。 -文件搜索:创建一个文件搜索工具,查找指定目录下所有特定类型的文件(如.js文件)。 +4.文件搜索:创建一个文件搜索工具,查找指定目录下所有特定类型的文件(如.js文件)。 -日志系统:创建一个简单的日志系统,支持写入日志到文件,包含时间戳和日志级别。 \ No newline at end of file +5.日志系统:创建一个简单的日志系统,支持写入日志到文件,包含时间戳和日志级别。 \ No newline at end of file -- Gitee From 6b9f07b0d496776452bb2a2cc354b36501678db5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B7=BC=E6=9E=97?= <3330918054@qq.com> Date: Fri, 20 Mar 2026 10:49:31 +0800 Subject: [PATCH 3/4] bji --- .../20260316-\347\273\203\344\271\240.md" | 137 ++++++++++++++++++ ...73\347\273\237\346\250\241\345\235\227.md" | 55 ++++++- 2 files changed, 191 insertions(+), 1 deletion(-) diff --git "a/\351\273\204\346\267\274\346\236\227/20260316-\347\273\203\344\271\240.md" "b/\351\273\204\346\267\274\346\236\227/20260316-\347\273\203\344\271\240.md" index e69de29..f5621fa 100644 --- "a/\351\273\204\346\267\274\346\236\227/20260316-\347\273\203\344\271\240.md" +++ "b/\351\273\204\346\267\274\346\236\227/20260316-\347\273\203\344\271\240.md" @@ -0,0 +1,137 @@ +```js +import fs from 'fs'; + +const FILE_PATH = './money.json'; + +let commander = process.argv[2]; +let params = process.argv[3]; + +if (commander == 'add') { + // 入账 + let arr = readFromJson(); + arr.push({ + amount: params * 1, + type: 'input', + timestamp: new Date() + }) + writeToJson(arr); + printAmount(); + +} else if (commander == 'del') { + // 出账 + let arr = readFromJson(); + arr.push({ + amount: params * 1, + type: 'output', + timestamp: new Date() + }) + writeToJson(arr); + printAmount(); + +} else if (commander == 'amount') { + printAmount(); + +} else if (commander == 'list') { + let arr = readFromJson(); + if (arr.length == 0) { + console.log('暂无收支记录'); + } else { + // 统计 + let inputSum = 0; + let outputSum = 0; + arr.forEach(item => { + if (item.type == 'input') { + inputSum += item.amount * 1; + } else { + outputSum += item.amount * 1; + } + }); + + console.log(''); + console.log('╔═══════════════════════════════════════════╗'); + console.log('║ 财富本 - 收支记录 ║'); + console.log('╠═══════════════════════════════════════════╣'); + + // 按时间倒序排列显示最近10条 + let sortedArr = arr.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp)); + let showArr = sortedArr.slice(0, 10); + + showArr.forEach((item, index) => { + let typeText = item.type == 'input' ? '📥 入账' : '📤 出账'; + let time = new Date(item.timestamp).toLocaleString('zh-CN'); + let amountText = item.type == 'input' + ? `+${item.amount} 元` + : `-${item.amount} 元`; + console.log(`║ ${index + 1}. ${typeText} ${amountText.padEnd(12)} ${time.slice(0, 10)} ║`); + }); + + if (arr.length > 10) { + console.log(`║ ... 还有 ${arr.length - 10} 条记录 ║`); + } + + console.log('╠═══════════════════════════════════════════╣'); + console.log(`║ 总收入:${inputSum.toString().padEnd(32)}║`); + console.log(`║ 总支出:${outputSum.toString().padEnd(32)}║`); + console.log('╠═══════════════════════════════════════════╣'); + console.log(`║ 当前余额:${(inputSum - outputSum).toString().padEnd(29)}║`); + console.log('╚═══════════════════════════════════════════╝'); + console.log(''); + } + +} else if (commander == 'clear') { + writeToJson([]); + console.log('已清除所有记录,当前余额为 0'); + +} else { + // 帮助信息 + console.log(` +╔═══════════════════════════════════════╗ +║ 财富管理系统 ║ +╠═══════════════════════════════════════╣ +║ 用法: ║ +║ node index.js add <金额> 入账 ║ +║ node index.js del <金额> 出账 ║ +║ node index.js amount 查看余额 ║ +║ node index.js list 查看记录 ║ +║ node index.js clear 清除记录 ║ +╚═══════════════════════════════════════╝ + `); +} + +// 从指定文件中读取所有数据 +function readFromJson() { + if (fs.existsSync(FILE_PATH)) { + let jsonString = fs.readFileSync(FILE_PATH, 'utf-8'); + if (jsonString.length > 0) { + return JSON.parse(jsonString); + } + return []; + } + return []; +} + +// 将数据写入文件 +function writeToJson(arr) { + let jsonString = JSON.stringify(arr); + fs.writeFileSync(FILE_PATH, jsonString); +} + +// 打印当前余额 +function printAmount() { + let arr = readFromJson(); + + let inputSum = 0; + let outputSum = 0; + + arr.forEach(item => { + if (item.type == 'input') { + inputSum += item.amount * 1; + } else if (item.type == 'output') { + outputSum += item.amount * 1; + } + }); + + let amount = inputSum - outputSum; + console.log('当前余额为:' + amount); +} +``` \ No newline at end of file diff --git "a/\351\273\204\346\267\274\346\236\227/20260319-\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227.md" "b/\351\273\204\346\267\274\346\236\227/20260319-\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227.md" index 548dddf..4e6d4fe 100644 --- "a/\351\273\204\346\267\274\346\236\227/20260319-\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227.md" +++ "b/\351\273\204\346\267\274\346\236\227/20260319-\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227.md" @@ -147,18 +147,71 @@ fs.rmSync('./backup', { recursive: true, force: true }); ### 简答题 1.请解释同步方法和异步方法的区别。 +- 同步方法(Sync):调用后会阻塞后续代码执行,直到方法完成并返回结果。程序按 “从上到下” 的顺序执行,结果直接通过返回值获取,出错时会抛出异常(需 try/catch 捕获)。 +- 异步方法(Async):调用后不会阻塞,立即返回,后续代码可继续执行;方法的结果通过回调函数、Promise、async/await 等方式返回,出错时通常在回调的错误参数(如 err)中体现。 + 2.fs.readFile和fs.readFileSync有什么区别? +|特性| fs.readFile(异步)| fs.readFileSync(同步)| +|-------| ----------------| --------------------- | +|执行方式| 非阻塞,立即返回| 阻塞,直到文件读取完成| +|结果获取| 通过回调函数(err, data)| 直接返回读取结果| +|错误处理| 回调的 err 参数接收| 需 try/catch 捕获| +|性能影响| 不阻塞主线程,适合高并发| 阻塞主线程,低并发场景可用| + 3.如何实现文件的追加写入? +方式 1:fs.appendFile(异步) +方式 2:fs.writeFile 配置 flag(推荐) +方式 3:流式追加(适合大文件) + 4.什么是流式处理?它适合什么场景? +(1)流式处理(Stream)是 Node.js 中处理大文件 / 持续数据的核心机制:它将数据拆分为 “小块(chunk)”,分批次读取 / 写入 / 处理,而非一次性加载整个文件到内存。 +(2)适合的场景 + - 处理大文件:如读取 1GB 的日志文件、视频文件(避免一次性加载导致内存溢出); + - 持续数据传输:如 HTTP 响应 / 请求、TCP 网络通信、管道(pipe)传输; + - 实时数据处理:如实时解析日志、流式压缩 / 加密数据; + - 效率优化:如边读取边写入(readStream.pipe(writeStream)),减少内存占用。 + 5.如何监听文件的变化? ### 操作题 1.文件读取器:创建一个程序,读取指定文件的内容并输出到控制台。 - +```js +const fs = require('fs'); +const path = require('path'); +// 同步读取文件 +function readFileSync(filePath) { + const absolutePath = path.resolve(filePath); + try { + const data = fs.readFileSync(absolutePath, 'utf8'); + console.log('===== 文件内容 ====='); + console.log(data); + console.log('===================='); + } catch (err) { + console.error('读取文件失败:', err.message); + } +} +``` 2.文件写入器:创建一个程序,接收命令行输入的内容,写入到文件中。 +```js +const fs = require('fs'); +const path = require('path'); +const readline = require('readline'); +function writeToFile(content, filePath) { + const absolutePath = path.resolve(filePath); + // 用 writeFile 写入 + fs.writeFile(absolutePath, content, 'utf8', (err) => { + if (err) { + console.error('写入文件失败:', err.message); + return; + } + console.log(`内容已成功写入 ${absolutePath}`); + rl.close(); // 关闭输入接口 + }); +} +``` 3.目录复制:实现一个函数,递归复制整个目录。 -- Gitee From d0bb78caf2c7c31845f61a20f2715c37bc504da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B7=BC=E6=9E=97?= <3330918054@qq.com> Date: Fri, 20 Mar 2026 17:01:51 +0800 Subject: [PATCH 4/4] =?UTF-8?q?20260320=E7=AC=94=E8=AE=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../20260320-http\346\250\241\345\235\227.md" | 303 ++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 "\351\273\204\346\267\274\346\236\227/20260320-http\346\250\241\345\235\227.md" diff --git "a/\351\273\204\346\267\274\346\236\227/20260320-http\346\250\241\345\235\227.md" "b/\351\273\204\346\267\274\346\236\227/20260320-http\346\250\241\345\235\227.md" new file mode 100644 index 0000000..fe1dc38 --- /dev/null +++ "b/\351\273\204\346\267\274\346\236\227/20260320-http\346\250\241\345\235\227.md" @@ -0,0 +1,303 @@ +## http模块笔记 +### 一、模块概述 +1. 学习意义 +- 日常访问网站、登录账号、接口请求等操作,均基于HTTP 协议实现浏览器与服务器的通信。 +2. 核心作用 + +|功能 |对应方法| +|--------------|---------------------| +|创建 Web 服务器| http.createServer()| +|发送 HTTP 请求 | http.request() / http.get()| +|解析请求信息 | 获取请求方法、URL、参数、请求头| +|返回响应数据 |发送 HTML、JSON、文本等| + +### 二、核心知识点 +知识点 1:创建基础 HTTP 服务器 +1. 最简服务器代码 +```js +javascript +运行 +// 引入http模块 +const http = require('http'); + +// 创建服务器:req=请求对象,res=响应对象 +const server = http.createServer((req, res) => { + // 设置响应头:状态码200=成功,内容类型=纯文本 + res.writeHead(200, { 'Content-Type': 'text/plain' }); + // 发送响应并结束请求 + res.end('Hello World!'); +}); + +// 监听3000端口,启动服务器 +server.listen(3000, () => { + console.log('服务器运行在 http://localhost:3000'); +}); +``` +2. 启动与访问 +- 保存为 server.js +- 命令行执行:node server.js +- 浏览器访问:http://localhost:3000 + +知识点 2:请求对象(req) +用于获取客户端发送的请求信息,常用属性: +```js +javascript +运行 +const server = http.createServer((req, res) => { + // 1. 请求方法:GET/POST/PUT/DELETE + console.log('请求方法:', req.method); + + // 2. 请求URL:/ /about /api/users + console.log('请求URL:', req.url); + + // 3. 请求头:浏览器信息、Cookie等 + console.log('浏览器信息:', req.headers['user-agent']); + + // 4. 解析URL(获取路径+查询参数) + const urlObj = new URL(req.url, `http://${req.headers.host}`); + console.log('请求路径:', urlObj.pathname); // 纯路径,不含参数 + console.log('查询参数name:', urlObj.searchParams.get('name')); // 获取?name=xxx + + res.end('请求解析完成'); +}); +``` +知识点 3:响应对象(res) +用于向客户端返回数据,核心方法: +```js +const server = http.createServer((req, res) => { + // 1. 设置响应状态码 + res.statusCode = 200; // 成功 + // res.statusCode = 404; // 页面未找到 + // res.statusCode = 500; // 服务器错误 + + // 2. 设置响应头(单个) + res.setHeader('Content-Type', 'text/html; charset=utf-8'); + + // 3. 批量设置响应头+状态码 + res.writeHead(200, { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*' // 解决跨域 + }); + + // 4. 发送响应数据(必须调用,结束请求) + res.end('

你好,Node.js

'); // 返回HTML + // res.end(JSON.stringify({ name: '张三' })); // 返回JSON +}); +``` +知识点 4:处理不同请求(路由 + 方法) +```js +const http = require('http'); +const server = http.createServer((req, res) => { + // 统一设置响应格式+跨域 + res.setHeader('Content-Type', 'application/json; charset=utf-8'); + res.setHeader('Access-Control-Allow-Origin', '*'); + + const urlObj = new URL(req.url, `http://${req.headers.host}`); + const pathname = urlObj.pathname; + + // 1. GET 获取所有用户 + if (req.method === 'GET' && pathname === '/api/users') { + res.end(JSON.stringify([{ id: 1, name: '张三' }])); + } + + // 2. POST 创建用户 + else if (req.method === 'POST' && pathname === '/api/users') { + let body = ''; + // 接收请求体数据 + req.on('data', chunk => body += chunk); + // 数据接收完成 + req.on('end', () => { + const user = JSON.parse(body); + res.end(JSON.stringify({ success: true, data: user })); + }); + } + + // 3. 404 未找到 + else { + res.statusCode = 404; + res.end(JSON.stringify({ error: '接口不存在' })); + } +}); +server.listen(3000); +``` +知识点 5:处理查询参数 +通过 URL 对象的 searchParams 获取 URL 中的参数: +```js +const http = require('http'); +const server = http.createServer((req, res) => { + const urlObj = new URL(req.url, `http://${req.headers.host}`); + + // 获取参数(无参数则返回null) + const name = urlObj.searchParams.get('name'); + const age = urlObj.searchParams.get('age'); + const page = urlObj.searchParams.get('page') || 1; // 默认值 + + res.writeHead(200, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify({ + message: `你好,${name || '游客'}`, + age, + page + })); +}); +server.listen(3000); +测试:http://localhost:3000?name=张三&age=20&page=2 +``` +知识点 6:HTTP 客户端(发送请求) +```js +//1. 发送 GET 请求 +const http = require('http'); +// 简化版:http.get() +http.get('http://localhost:3000/api/users', (res) => { + let data = ''; + // 接收响应数据 + res.on('data', chunk => data += chunk); + // 响应完成 + res.on('end', () => console.log('响应结果:', data)); +}); + +//2. 发送 POST 请求 + +const http = require('http'); +const postData = JSON.stringify({ name: '李四', age: 22 }); + +const options = { + hostname: 'localhost', + port: 3000, + path: '/api/users', + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': Buffer.byteLength(postData) + } +}; + +// 发送请求 +const req = http.request(options, (res) => { + let data = ''; + res.on('data', chunk => data += chunk); + res.on('end', () => console.log('响应:', data)); +}); + +// 发送请求体数据 +req.write(postData); +req.end(); +``` +### 三、实战练习 + +练习 1:简单页面服务器 +```js +const http = require('http'); +const server = http.createServer((req, res) => { + const urlObj = new URL(req.url, `http://${req.headers.host}`); + const pathname = urlObj.pathname; + + res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); + let content = ''; + + switch(pathname) { + case '/': + content = '

首页

欢迎访问我的网站

'; + break; + case '/about': + content = '

关于我们

Node.js 学习项目

'; + break; + case '/contact': + content = '

联系我们

邮箱:test@123.com

'; + break; + default: + res.statusCode = 404; + content = '

404

页面不存在

'; + } + + res.end(content); +}); +server.listen(3000, () => console.log('服务器启动:http://localhost:3000')); +``` +练习 2:RESTful 用户 API +```js +//实现用户的增删查接口: + +const http = require('http'); +// 模拟用户数据 +let users = [{ id: 1, name: '张三' }, { id: 2, name: '李四' }]; + +const server = http.createServer((req, res) => { + res.setHeader('Content-Type', 'application/json; charset=utf-8'); + res.setHeader('Access-Control-Allow-Origin', '*'); + const pathname = new URL(req.url, `http://${req.headers.host}`).pathname; + + // 查询所有用户 + if (req.method === 'GET' && pathname === '/api/users') { + res.end(JSON.stringify(users)); + } + + // 新增用户 + else if (req.method === 'POST' && pathname === '/api/users') { + let body = ''; + req.on('data', chunk => body += chunk); + req.on('end', () => { + const newUser = JSON.parse(body); + newUser.id = users.length + 1; + users.push(newUser); + res.end(JSON.stringify({ success: true, user: newUser })); + }); + } + + // 404 + else { + res.statusCode = 404; + res.end(JSON.stringify({ error: '接口不存在' })); + } +}); +server.listen(3001, () => console.log('API服务:http://localhost:3001')); +``` +### 四、核心总结 +- 创建服务器:http.createServer((req, res) => {}) + listen(端口) +- 请求解析:req.method(方法)、req.url(路径)、URL 对象(解析参数) +- 响应返回:res.writeHead(设置头)、res.end(发送数据) +- 客户端请求:http.get()(GET)、http.request()(所有方法) +- 常用格式:接口返回 JSON,页面返回 HTML,统一处理跨域和编码 + + +## 练习 +### 简答题 +1.请解释req和res分别代表什么? + +(1)req 是请求对象(request),代表客户端发送过来的 HTTP 请求,我们通过它能获取请求方法、请求 URL、请求头、查询参数、请求体等客户端信息。 + +(2)res 是响应对象(response),代表服务器要返回给客户端的 HTTP 响应,我们通过它设置状态码、响应头、响应内容,最终把数据返回给客户端。 + +2.http.createServer的回调函数接收哪些参数? + +- 回调函数固定接收两个参数,顺序不能改变: + + - 第一个参数是 req(请求对象),第二个参数是 res(响应对象)。 + +3.如何获取URL中的查询参数? + +- 先通过 new URL () 解析完整的请求 URL,再用 searchParams.get () 方法获取具体的查询参数。 + + - 步骤:① 创建 URL 对象;② 调用 searchParams.get (' 参数名 ') 获取对应值。 + +4.res.writeHead和res.setHeader有什么区别? + +- res.setHeader 是单独设置一个响应头,可以多次调用设置不同头,不修改状态码。 + +- res.writeHead 是一次性设置状态码 + 多个响应头,只能调用一次,会覆盖之前单独设置的响应头,适合批量配置。 + +5.http.get和http.request有什么区别? + +- http.get 是简化版的 GET 请求方法,只能发送 GET 请求,无需手动调用 req.end (),使用更简便。 + +- http.request 是完整版请求方法,支持 GET、POST、PUT、DELETE 等所有请求方法,需要手动调用 req.end () 结束请求,功能更全面灵活。 + +### 操作题 +1.静态服务器:创建一个Web服务器,返回HTML页面,包含CSS样式。 + +2.计算器API:创建RESTful API,支持加、减、乘、除运算。 + +3.图片服务器:创建一个简单的图片服务器,根据URL返回指定目录下的图片。 + +4.天气查询:创建一个天气查询工具,调用第三方API获取天气信息。 + +5.代理服务器:创建一个简单的代理服务器,将请求转发到另一个服务器。 \ No newline at end of file -- Gitee