Node.js核心模块实战:文件、路径、HTTP与流处理
预计时间:3-4 天
🎯 本章目标
掌握 Node.js 最常用的内置模块,理解文件操作、HTTP 服务、流和事件驱动编程。
1. fs(文件系统)
Promise 版本(推荐)
typescript
import { readFile, writeFile, readdir, stat, mkdir, rm } from 'fs/promises';
import { join } from 'path';
// 读文件
const content = await readFile('data.txt', 'utf-8');
// 写文件(覆盖)
await writeFile('output.txt', 'Hello World', 'utf-8');
// 追加内容
import { appendFile } from 'fs/promises';
await appendFile('log.txt', 'new log line\n');
// 读目录
const files = await readdir('./src');
const filesWithTypes = await readdir('./src', { withFileTypes: true });
// 获取文件信息
const info = await stat('data.txt');
console.log(info.isFile()); // true
console.log(info.isDirectory()); // false
console.log(info.size); // 文件大小(字节)
// 创建目录(recursive: true 类似 mkdir -p)
await mkdir('./dist/logs', { recursive: true });
// 删除(recursive: true 删除目录及内容)
await rm('./dist', { recursive: true, force: true });
文件监听(开发热重载原理)
typescript
import { watch } from 'fs';
const watcher = watch('./src', { recursive: true }, (event, filename) => {
console.log(`${filename} was ${event}`); // 'change' | 'rename'
});
// 关闭监听
watcher.close();
2. path(路径处理)
typescript
import { join, resolve, dirname, basename, extname, parse } from 'path';
// join --- 拼接路径(自动处理分隔符)
join('/users', 'tom', 'file.txt'); // '/users/tom/file.txt'
// resolve --- 解析为绝对路径
resolve('src', 'index.ts'); // '/absolute/path/to/src/index.ts'
// dirname --- 获取目录部分
dirname('/users/tom/file.txt'); // '/users/tom'
// basename --- 获取文件名
basename('/users/tom/file.txt'); // 'file.txt'
basename('/users/tom/file.txt', '.txt'); // 'file'
// extname --- 获取扩展名
extname('file.txt'); // '.txt'
// parse --- 解析路径各部分
parse('/users/tom/file.txt');
// { root: '/', dir: '/users/tom', base: 'file.txt', ext: '.txt', name: 'file' }
跨平台注意 :
path.join会自动使用当前系统的路径分隔符(Windows\,Linux/)。
3. http(HTTP 服务器)
原生 HTTP 服务器
typescript
import { createServer, IncomingMessage, ServerResponse } from 'http';
const server = createServer((req: IncomingMessage, res: ServerResponse) => {
const { method, url } = req;
if (method === 'GET' && url === '/api/users') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify([{ id: 1, name: 'Tom' }]));
return;
}
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Not Found' }));
});
server.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
原生 http 模块太底层,实际项目用 Express / NestJS,但理解原理很重要。
HTTP 客户端请求
typescript
// 推荐使用内置的 fetch(Node 18+)
const res = await fetch('https://api.example.com/users');
const data = await res.json();
// 或使用 axios(第三方库,功能更丰富)
import axios from 'axios';
const { data } = await axios.get('https://api.example.com/users');
4. events(事件驱动)
EventEmitter
typescript
import { EventEmitter } from 'events';
// EventEmitter 是 Node.js 事件驱动的核心
// 类似 Java 的观察者模式 / Spring 的 ApplicationEvent
class OrderService extends EventEmitter {
async createOrder(order: any) {
// 保存订单...
this.emit('order:created', order); // 触发事件
}
}
const orderService = new OrderService();
// 监听事件
orderService.on('order:created', (order) => {
console.log('发送确认邮件:', order.id);
});
orderService.on('order:created', (order) => {
console.log('更新库存:', order.items);
});
await orderService.createOrder({ id: 1, items: ['item1'] });
// 两个监听器都会执行
常用方法
typescript
emitter.on(event, listener); // 注册监听器
emitter.once(event, listener); // 只触发一次
emitter.off(event, listener); // 移除监听器
emitter.emit(event, ...args); // 触发事件
emitter.removeAllListeners(); // 移除所有监听器
注意 :默认情况下,同一事件最多 10 个监听器,超过会警告。可用
emitter.setMaxListeners(n)修改。
5. stream(流)
为什么需要流
处理 1GB 文件:
❌ readFile --- 一次性读入内存,占用 1GB
✅ createReadStream --- 分块读取,每次只占 64KB
四种流类型
| 类型 | 说明 | 示例 |
|---|---|---|
| Readable | 可读流 | HTTP 请求、文件读取 |
| Writable | 可写流 | HTTP 响应、文件写入 |
| Duplex | 可读可写 | TCP Socket |
| Transform | 转换流 | 压缩、加密 |
文件流
typescript
import { createReadStream, createWriteStream } from 'fs';
import { pipeline } from 'stream/promises';
// 读流
const readStream = createReadStream('large-file.txt', {
encoding: 'utf-8',
highWaterMark: 64 * 1024 // 每次读 64KB
});
readStream.on('data', (chunk) => {
console.log('读取了:', chunk.length, '字节');
});
readStream.on('end', () => console.log('读取完成'));
readStream.on('error', (err) => console.error(err));
// 管道(最简洁的方式)--- 类似 Java 的 Stream pipeline
await pipeline(
createReadStream('input.txt'),
createWriteStream('output.txt')
);
流 + 压缩
typescript
import { createGzip } from 'zlib';
await pipeline(
createReadStream('input.txt'),
createGzip(),
createWriteStream('input.txt.gz')
);
HTTP 响应也是流
typescript
import { createServer } from 'http';
import { createReadStream } from 'fs';
const server = createServer((req, res) => {
// 流式传输文件(不会一次性加载到内存)
const stream = createReadStream('large-video.mp4');
stream.pipe(res);
});
6. child_process(子进程)
typescript
import { exec, spawn, execFile } from 'child_process';
import { promisify } from 'util';
const execAsync = promisify(exec);
// exec --- 执行 shell 命令(适合短命令)
const { stdout, stderr } = await execAsync('ls -la');
console.log(stdout);
// spawn --- 启动子进程(适合长时间运行的进程)
const child = spawn('node', ['worker.js'], {
stdio: 'pipe' // 捕获输出
});
child.stdout.on('data', (data) => {
console.log('子进程输出:', data.toString());
});
child.on('exit', (code) => {
console.log('子进程退出,退出码:', code);
});
7. cluster(集群,了解)
typescript
// Node.js 单线程,用 cluster 利用多核 CPU
import cluster from 'cluster';
import { cpus } from 'os';
import { createServer } from 'http';
if (cluster.isPrimary) {
const numCPUs = cpus().length;
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker) => {
console.log(`Worker ${worker.process.pid} died, restarting...`);
cluster.fork();
});
} else {
createServer((req, res) => {
res.end(`Hello from worker ${process.pid}`);
}).listen(3000);
}
实际项目:通常用 PM2 或 Docker 来管理多进程,不直接用 cluster。
下一步:包管理与工程化