Node.js核心模块实战:文件、路径、HTTP与流处理

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。


下一步:包管理与工程化

相关推荐
糖拌西瓜皮1 小时前
Node.js工程化实践:包管理、TypeScript配置与代码质量
typescript·node.js
糖拌西瓜皮1 小时前
NestJS入门指南:Java开发者的Spring Boot体验
javascript·node.js
糖拌西瓜皮1 小时前
Express框架快速上手:中间件、路由与错误处理
javascript·node.js
半个落月4 小时前
从递归到快速排序:用 JavaScript 把分治思想讲明白
javascript·算法·面试
半个落月4 小时前
从 Tokenization 到 Embedding:用 Node.js 搞懂大模型为什么先“分词”再“向量化”
人工智能·node.js
小兔崽子去哪了4 小时前
Vue3 + Pinia 集成 IGV.js 实现 BAM 文件在线浏览
javascript·vue.js·后端
小月土星5 小时前
JavaScript 快速排序:从 pivot、双指针到分治思想
javascript·算法·面试
小月土星5 小时前
JavaScript 递归入门:从 1 到 n 求和,再到数组扁平化
javascript·算法·面试
还有多久拿退休金5 小时前
一个 var 让整个团队加班到凌晨——JS 闭包的那些暗坑
前端·javascript