Bun 文件操作 #
概述 #
Bun 提供了简洁高效的文件操作 API,包括 Bun.file()、Bun.write() 和文件监控功能。这些 API 基于 Web 标准设计,使用 Promise 进行异步操作。
Bun.file() #
创建文件引用 #
typescript
// 创建文件引用
const file = Bun.file("./data.txt");
// 从路径创建
const file2 = Bun.file("/absolute/path/to/file.txt");
// 从相对路径创建
const file3 = Bun.file(import.meta.dir + "/data.txt");
文件属性 #
typescript
const file = Bun.file("./data.txt");
// 文件信息
console.log(file.size); // 文件大小(字节)
console.log(file.type); // MIME 类型
console.log(file.name); // 文件名
console.log(file.lastModified); // 最后修改时间
// 检查文件是否存在
const exists = await file.exists();
console.log("File exists:", exists);
读取文件内容 #
typescript
const file = Bun.file("./data.txt");
// 读取为文本
const text = await file.text();
console.log(text);
// 读取为 JSON
const jsonFile = Bun.file("./data.json");
const data = await jsonFile.json();
console.log(data);
// 读取为 ArrayBuffer
const buffer = await file.arrayBuffer();
// 读取为 Blob
const blob = file.slice(0, 1024);
// 读取为流
const stream = file.stream();
const reader = stream.getReader();
文件切片 #
typescript
const file = Bun.file("./large-file.bin");
// 读取部分内容
const chunk1 = file.slice(0, 1024); // 前 1KB
const chunk2 = file.slice(1024, 2048); // 第二个 1KB
const chunk3 = file.slice(1024); // 从 1KB 到末尾
// 读取切片内容
const text1 = await chunk1.text();
处理不同文件类型 #
typescript
// 文本文件
const textFile = Bun.file("./readme.txt");
const text = await textFile.text();
// JSON 文件
const jsonFile = Bun.file("./config.json");
const config = await jsonFile.json();
// 图片文件
const imageFile = Bun.file("./image.png");
const imageBuffer = await imageFile.arrayBuffer();
// 大文件流式读取
const largeFile = Bun.file("./video.mp4");
const stream = largeFile.stream();
Bun.write() #
写入文本 #
typescript
// 写入文本
await Bun.write("./output.txt", "Hello, Bun!");
// 覆盖写入
await Bun.write("./output.txt", "New content");
写入 JSON #
typescript
// 写入 JSON 对象
await Bun.write("./data.json", { name: "Bun", version: 1.2 });
// 格式化 JSON
const data = { name: "Bun", features: ["fast", "simple"] };
await Bun.write("./data.json", JSON.stringify(data, null, 2));
写入二进制数据 #
typescript
// 写入 ArrayBuffer
const buffer = new TextEncoder().encode("Binary data");
await Bun.write("./binary.bin", buffer);
// 写入 Uint8Array
const uint8Array = new Uint8Array([72, 101, 108, 108, 111]);
await Bun.write("./hello.bin", uint8Array);
写入 Blob #
typescript
// 写入 Blob
const blob = new Blob(["Hello, Blob!"], { type: "text/plain" });
await Bun.write("./blob.txt", blob);
// 从 Blob 创建文件
const imageBlob = new Blob([imageData], { type: "image/png" });
await Bun.write("./image.png", imageBlob);
复制文件 #
typescript
// 复制文件
const source = Bun.file("./source.txt");
await Bun.write("./dest.txt", source);
// 复制大文件
const largeFile = Bun.file("./large.mp4");
await Bun.write("./copy.mp4", largeFile);
写入选项 #
typescript
// 创建目录(如果不存在)
await Bun.write("./new-dir/file.txt", "content");
// 设置权限(Unix)
await Bun.write("./script.sh", "#!/bin/bash\necho hello", {
createPath: true,
});
目录操作 #
创建目录 #
typescript
import { mkdir } from "fs/promises";
// 创建目录
await mkdir("./new-dir");
// 递归创建
await mkdir("./deep/nested/dirs", { recursive: true });
读取目录 #
typescript
import { readdir } from "fs/promises";
// 读取目录
const files = await readdir("./src");
console.log(files);
// 递归读取
const allFiles = await readdir("./src", { recursive: true });
console.log(allFiles);
// 带文件类型
import { readdirSync, Dirent } from "fs";
const entries = readdirSync("./src", { withFileTypes: true });
for (const entry of entries as Dirent[]) {
console.log(`${entry.name} - ${entry.isDirectory() ? "DIR" : "FILE"}`);
}
删除目录 #
typescript
import { rm, rmdir } from "fs/promises";
// 删除空目录
await rmdir("./empty-dir");
// 递归删除
await rm("./dir", { recursive: true, force: true });
遍历目录 #
typescript
import { readdir, stat } from "fs/promises";
import { join } from "path";
async function walkDir(dir: string): Promise<string[]> {
const files: string[] = [];
const entries = await readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = join(dir, entry.name);
if (entry.isDirectory()) {
files.push(...await walkDir(fullPath));
} else {
files.push(fullPath);
}
}
return files;
}
const allFiles = await walkDir("./src");
console.log(allFiles);
文件信息 #
获取文件状态 #
typescript
import { stat, lstat } from "fs/promises";
// 获取文件状态
const stats = await stat("./file.txt");
console.log(stats.isFile()); // 是否是文件
console.log(stats.isDirectory()); // 是否是目录
console.log(stats.size); // 文件大小
console.log(stats.mtime); // 修改时间
console.log(stats.atime); // 访问时间
console.log(stats.ctime); // 创建时间
console.log(stats.mode); // 权限模式
// 符号链接状态
const linkStats = await lstat("./symlink");
console.log(linkStats.isSymbolicLink());
检查文件存在 #
typescript
import { access, constants } from "fs/promises";
// 检查文件是否存在
try {
await access("./file.txt", constants.F_OK);
console.log("File exists");
} catch {
console.log("File does not exist");
}
// 检查读写权限
try {
await access("./file.txt", constants.R_OK | constants.W_OK);
console.log("File is readable and writable");
} catch {
console.log("File is not accessible");
}
// 使用 Bun.file
const file = Bun.file("./file.txt");
const exists = await file.exists();
文件监控 #
Bun.watch() #
typescript
// 监控文件变化
const watcher = Bun.watch("./src", {
recursive: true,
});
watcher.on("change", (event, filename) => {
console.log(`File changed: ${filename}`);
console.log(`Event: ${event}`); // "change", "create", "delete"
});
watcher.on("error", (error) => {
console.error("Watch error:", error);
});
// 关闭监控
watcher.close();
监控特定文件 #
typescript
const watcher = Bun.watch("./config.json");
watcher.on("change", async (event, filename) => {
console.log(`${filename} was ${event}`);
// 重新加载配置
const config = await Bun.file("./config.json").json();
console.log("New config:", config);
});
使用 fs.watch #
typescript
import { watch } from "fs";
const watcher = watch("./src", { recursive: true }, (event, filename) => {
console.log(`${filename} - ${event}`);
});
watcher.on("error", (error) => {
console.error("Watch error:", error);
});
// 关闭
watcher.close();
流式处理 #
读取流 #
typescript
const file = Bun.file("./large-file.txt");
const stream = file.stream();
const reader = stream.getReader();
let result = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
result += new TextDecoder().decode(value);
}
console.log(result);
写入流 #
typescript
import { createWriteStream } from "fs";
const writeStream = createWriteStream("./output.txt");
writeStream.write("Line 1\n");
writeStream.write("Line 2\n");
writeStream.write("Line 3\n");
writeStream.end();
管道流 #
typescript
import { createReadStream, createWriteStream } from "fs";
import { pipeline } from "stream/promises";
await pipeline(
createReadStream("./source.txt"),
createWriteStream("./dest.txt")
);
console.log("File copied");
Transform 流 #
typescript
import { Transform, pipeline } from "stream";
const upperCase = new Transform({
transform(chunk, encoding, callback) {
callback(null, chunk.toString().toUpperCase());
},
});
await pipeline(
createReadStream("./input.txt"),
upperCase,
createWriteStream("./output.txt")
);
临时文件 #
创建临时文件 #
typescript
import { mkdtemp, writeFile } from "fs/promises";
import { tmpdir } from "os";
import { join } from "path";
// 创建临时目录
const tempDir = await mkdtemp(join(tmpdir(), "bun-"));
console.log("Temp dir:", tempDir);
// 创建临时文件
const tempFile = join(tempDir, "temp.txt");
await writeFile(tempFile, "Temporary content");
// 读取
const content = await Bun.file(tempFile).text();
console.log(content);
// 清理
import { rm } from "fs/promises";
await rm(tempDir, { recursive: true });
文件权限 #
修改权限 #
typescript
import { chmod, chown } from "fs/promises";
// 修改权限
await chmod("./script.sh", 0o755); // rwxr-xr-x
// 修改所有者
await chown("./file.txt", 1000, 1000); // uid, gid
符号链接 #
typescript
import { symlink, readlink, unlink } from "fs/promises";
// 创建符号链接
await symlink("./target.txt", "./link.txt");
// 读取链接目标
const target = await readlink("./link.txt");
console.log("Link target:", target);
// 删除链接
await unlink("./link.txt");
实用工具函数 #
递归复制目录 #
typescript
import { cp, mkdir } from "fs/promises";
import { dirname } from "path";
async function copyDir(src: string, dest: string) {
await mkdir(dest, { recursive: true });
await cp(src, dest, { recursive: true });
}
await copyDir("./src", "./backup");
查找文件 #
typescript
import { readdir, stat } from "fs/promises";
import { join, extname } from "path";
async function findFiles(
dir: string,
predicate: (name: string) => boolean
): Promise<string[]> {
const results: string[] = [];
const entries = await readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = join(dir, entry.name);
if (entry.isDirectory()) {
results.push(...await findFiles(fullPath, predicate));
} else if (predicate(entry.name)) {
results.push(fullPath);
}
}
return results;
}
// 查找所有 TypeScript 文件
const tsFiles = await findFiles("./src", (name) => name.endsWith(".ts"));
console.log(tsFiles);
文件大小格式化 #
typescript
function formatSize(bytes: number): string {
const units = ["B", "KB", "MB", "GB", "TB"];
let size = bytes;
let unitIndex = 0;
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex++;
}
return `${size.toFixed(2)} ${units[unitIndex]}`;
}
const stats = await stat("./large-file.bin");
console.log(`Size: ${formatSize(stats.size)}`);
最佳实践 #
错误处理 #
typescript
async function safeReadFile(path: string): Promise<string | null> {
try {
const file = Bun.file(path);
if (await file.exists()) {
return await file.text();
}
return null;
} catch (error) {
console.error(`Error reading ${path}:`, error);
return null;
}
}
并发文件操作 #
typescript
// 并发读取多个文件
const files = ["a.txt", "b.txt", "c.txt"];
const contents = await Promise.all(
files.map((f) => Bun.file(f).text())
);
console.log(contents);
流式处理大文件 #
typescript
async function processLargeFile(path: string) {
const file = Bun.file(path);
const stream = file.stream();
const reader = stream.getReader();
const decoder = new TextDecoder();
let lineBuffer = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
lineBuffer += decoder.decode(value, { stream: true });
const lines = lineBuffer.split("\n");
lineBuffer = lines.pop() || "";
for (const line of lines) {
// 处理每一行
console.log(line);
}
}
}
下一步 #
现在你已经了解了 Bun 的文件操作,接下来学习 SQLite 数据库 深入了解 Bun 的内置数据库功能。
最后更新:2026-03-29