Bun 文件操作
Bun 提供了高性能的文件 I/O API,比 Node.js 的 fs 模块更快且更易用。本章介绍 Bun 的文件操作方法。
Bun.file() API
创建文件引用
typescript
// 创建文件引用(不会立即读取)
const file = Bun.file("./data.txt");
// 文件信息
console.log(file.name); // 文件路径
console.log(file.size); // 文件大小(字节)
console.log(file.type); // MIME 类型读取文件内容
typescript
const file = Bun.file("./data.txt");
// 读取为文本
const text = await file.text();
console.log(text);
// 读取为 JSON
const jsonFile = Bun.file("./config.json");
const config = await jsonFile.json();
console.log(config);
// 读取为 ArrayBuffer
const buffer = await file.arrayBuffer();
// 读取为 Blob
const blob = await file.blob();
// 读取为 Uint8Array
const bytes = await file.bytes();检查文件是否存在
typescript
const file = Bun.file("./maybe-exists.txt");
// 检查文件是否存在
const exists = await file.exists();
console.log(exists ? "文件存在" : "文件不存在");写入文件
Bun.write()
typescript
// 写入文本
await Bun.write("./output.txt", "Hello, Bun!");
// 写入 JSON
await Bun.write("./data.json", JSON.stringify({ name: "Bun" }, null, 2));
// 写入二进制数据
const bytes = new Uint8Array([72, 101, 108, 108, 111]);
await Bun.write("./binary.bin", bytes);
// 写入 Response 对象
const response = await fetch("https://example.com/image.png");
await Bun.write("./image.png", response);
// 写入 Blob
const blob = new Blob(["Hello World"], { type: "text/plain" });
await Bun.write("./blob.txt", blob);写入选项
typescript
// 追加模式
const writer = Bun.file("./log.txt").writer();
writer.write("第一行\n");
writer.write("第二行\n");
await writer.end();流式读写
读取流
typescript
const file = Bun.file("./large-file.txt");
// 获取可读流
const stream = file.stream();
// 使用 for await 逐块读取
for await (const chunk of stream) {
console.log("读取块:", chunk.length, "字节");
}写入流
typescript
const file = Bun.file("./output.txt");
const writer = file.writer();
// 写入数据
writer.write("第一行\n");
writer.write("第二行\n");
writer.write(new Uint8Array([65, 66, 67]));
// 完成写入
await writer.end();管道操作
typescript
// 从一个文件复制到另一个
const source = Bun.file("./source.txt");
const dest = Bun.file("./dest.txt");
await Bun.write(dest, source);目录操作
读取目录
typescript
import { readdir, readdirSync } from "node:fs/promises";
// 异步读取目录
const files = await readdir("./src");
console.log(files);
// 包含文件类型信息
const entries = await readdir("./src", { withFileTypes: true });
for (const entry of entries) {
console.log(
entry.name,
entry.isDirectory() ? "目录" : "文件"
);
}使用 Bun 的 glob
typescript
// 使用 glob 匹配文件
const glob = new Bun.Glob("**/*.ts");
// 遍历匹配的文件
for await (const file of glob.scan("./src")) {
console.log(file);
}
// 获取所有匹配文件
const files = await Array.fromAsync(glob.scan("./src"));
console.log(files);创建目录
typescript
import { mkdir } from "node:fs/promises";
// 创建目录
await mkdir("./new-folder");
// 递归创建
await mkdir("./a/b/c", { recursive: true });删除目录
typescript
import { rmdir, rm } from "node:fs/promises";
// 删除空目录
await rmdir("./empty-folder");
// 递归删除(包含内容)
await rm("./folder-with-content", { recursive: true });文件信息
获取文件状态
typescript
import { stat, lstat } from "node:fs/promises";
const stats = await stat("./file.txt");
console.log({
大小: stats.size,
是文件: stats.isFile(),
是目录: stats.isDirectory(),
是符号链接: stats.isSymbolicLink(),
创建时间: stats.birthtime,
修改时间: stats.mtime,
访问时间: stats.atime,
});使用 Bun.file() 获取信息
typescript
const file = Bun.file("./file.txt");
console.log({
路径: file.name,
大小: file.size,
类型: file.type,
最后修改: file.lastModified,
});文件路径操作
path 模块
typescript
import path from "node:path";
// 拼接路径
const fullPath = path.join("./src", "utils", "helper.ts");
// "./src/utils/helper.ts"
// 解析为绝对路径
const absolute = path.resolve("./file.txt");
// "/Users/xxx/project/file.txt"
// 获取目录名
const dir = path.dirname("/path/to/file.txt");
// "/path/to"
// 获取文件名
const base = path.basename("/path/to/file.txt");
// "file.txt"
// 获取扩展名
const ext = path.extname("/path/to/file.txt");
// ".txt"
// 解析路径
const parsed = path.parse("/path/to/file.txt");
// { root: '/', dir: '/path/to', base: 'file.txt', ext: '.txt', name: 'file' }特殊路径
typescript
// 当前工作目录
console.log(process.cwd());
// 当前文件目录
console.log(import.meta.dir);
// 当前文件路径
console.log(import.meta.path);
// 主模块目录
console.log(Bun.main);文件复制和移动
复制文件
typescript
import { copyFile } from "node:fs/promises";
// 使用 Node.js API
await copyFile("./source.txt", "./dest.txt");
// 使用 Bun.write
const source = Bun.file("./source.txt");
await Bun.write("./dest.txt", source);移动/重命名文件
typescript
import { rename } from "node:fs/promises";
// 重命名
await rename("./old-name.txt", "./new-name.txt");
// 移动文件
await rename("./file.txt", "./folder/file.txt");临时文件
创建临时文件
typescript
import { tmpdir } from "node:os";
import path from "node:path";
// 获取临时目录
const tempDir = tmpdir();
// 创建临时文件
const tempFile = path.join(tempDir, `temp-${Date.now()}.txt`);
await Bun.write(tempFile, "临时内容");
console.log("临时文件:", tempFile);使用 Bun 临时文件
typescript
// Bun 自动创建临时文件
const tempFile = Bun.file("/tmp/my-temp-file.txt");
await Bun.write(tempFile, "临时数据");监听文件变化
使用 Bun.watch (实验性)
typescript
import { watch } from "node:fs";
// 监听文件变化
const watcher = watch("./src", { recursive: true }, (event, filename) => {
console.log(`文件 ${filename} 发生 ${event} 事件`);
});
// 停止监听
// watcher.close();实际应用
typescript
// 监听配置文件变化并重新加载
import { watch } from "node:fs";
let config = await loadConfig();
watch("./config.json", async (event) => {
if (event === "change") {
console.log("配置文件已更改,重新加载...");
config = await loadConfig();
}
});
async function loadConfig() {
return Bun.file("./config.json").json();
}实际应用示例
日志记录器
typescript
// logger.ts
class Logger {
private logFile: string;
private writer: ReturnType<typeof Bun.file.prototype.writer> | null = null;
constructor(logFile: string) {
this.logFile = logFile;
}
private async getWriter() {
if (!this.writer) {
this.writer = Bun.file(this.logFile).writer();
}
return this.writer;
}
async log(level: string, message: string) {
const timestamp = new Date().toISOString();
const line = `[${timestamp}] [${level}] ${message}\n`;
const writer = await this.getWriter();
writer.write(line);
// 同时输出到控制台
console.log(line.trim());
}
async info(message: string) {
await this.log("INFO", message);
}
async error(message: string) {
await this.log("ERROR", message);
}
async close() {
if (this.writer) {
await this.writer.end();
this.writer = null;
}
}
}
// 使用
const logger = new Logger("./app.log");
await logger.info("应用启动");
await logger.error("发生错误");
await logger.close();文件上传处理
typescript
// upload-server.ts
const server = Bun.serve({
port: 3000,
async fetch(request) {
if (request.method === "POST" && request.url.endsWith("/upload")) {
const formData = await request.formData();
const file = formData.get("file") as File;
if (!file) {
return new Response("没有上传文件", { status: 400 });
}
// 保存文件
const savePath = `./uploads/${file.name}`;
await Bun.write(savePath, file);
return Response.json({
message: "上传成功",
filename: file.name,
size: file.size,
});
}
return new Response("上传接口: POST /upload", { status: 200 });
},
});
console.log(`上传服务器运行在 http://localhost:${server.port}`);配置文件管理
typescript
// config-manager.ts
class ConfigManager<T> {
private configPath: string;
private cache: T | null = null;
constructor(configPath: string) {
this.configPath = configPath;
}
async load(): Promise<T> {
if (this.cache) return this.cache;
const file = Bun.file(this.configPath);
if (!(await file.exists())) {
throw new Error(`配置文件不存在: ${this.configPath}`);
}
this.cache = await file.json();
return this.cache!;
}
async save(config: T): Promise<void> {
await Bun.write(
this.configPath,
JSON.stringify(config, null, 2)
);
this.cache = config;
}
async update(updates: Partial<T>): Promise<T> {
const current = await this.load();
const updated = { ...current, ...updates };
await this.save(updated);
return updated;
}
invalidateCache(): void {
this.cache = null;
}
}
// 使用
interface AppConfig {
port: number;
debug: boolean;
apiKey: string;
}
const configManager = new ConfigManager<AppConfig>("./config.json");
const config = await configManager.load();
console.log("当前配置:", config);
await configManager.update({ debug: true });性能对比
Bun 文件 I/O 比 Node.js 快得多:
读取 1MB 文件:
Node.js fs.readFile: 5ms
Bun.file().text(): 1ms
写入 1MB 文件:
Node.js fs.writeFile: 10ms
Bun.write(): 2ms小结
本章介绍了:
- ✅ Bun.file() 和 Bun.write() API
- ✅ 流式读写大文件
- ✅ 目录操作和 glob 匹配
- ✅ 文件信息和路径操作
- ✅ 文件监听和临时文件
- ✅ 实际应用示例
下一步
继续阅读 HTTP 服务器 了解如何使用 Bun 创建高性能 Web 服务器。