关于 bun-file-io
面向 Bun 开发者的文件 I/O 技能指南,介绍 Bun 与 Node.js 的常见文件操作,并涵盖流、目录、路径和文件监视模式。
主要功能
- 01读取文本、JSON 和二进制文件
- 02写入和追加文件内容
- 03流式处理及传输文件数据
- 04管理目录和文件元数据
- 05使用 glob 模式扫描文件
- 06监视文件并创建临时目录
适用场景
- 01加载 JSON 配置文件
- 02分块处理大型文件
- 03复制或下载数据到文件
- 04按 glob 模式查找源文件
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ secondsky/ claude-skills --skill bun-file-io安装后在 Claude Code 中输入/bun-file-io确认已加载。
详细介绍
Bun 文件 I/O
Bun 通过 Bun.file() 和 Bun.write() 提供快速、优化的文件操作。
读取文件
Bun.file()
// Create file reference (lazy, doesn't read yet)
const file = Bun.file("./data.txt");
// File properties
console.log(file.size); // Size in bytes
console.log(file.type); // MIME type
console.log(file.name); // File path
console.log(await file.exists()); // Boolean
// Read content
const text = await file.text();
const json = await file.json();
const buffer = await file.arrayBuffer();
const bytes = await file.bytes(); // Uint8Array
const stream = file.stream(); // ReadableStream
读取特定类型
// JSON file
const config = await Bun.file("config.json").json();
// Text file
const content = await Bun.file("readme.md").text();
// Binary file
const binary = await Bun.file("image.png").arrayBuffer();
// With import attributes
import data from "./data.json" with { type: "json" };
import text from "./content.txt" with { type: "text" };
写入文件
Bun.write()
// Write string
await Bun.write("./output.txt", "Hello World");
// Write JSON
await Bun.write("./data.json", JSON.stringify({ key: "value" }, null, 2));
// Write binary
await Bun.write("./output.bin", new Uint8Array([1, 2, 3]));
// Write from Response
const response = await fetch("https://example.com/image.png");
await Bun.write("./image.png", response);
// Write from another file (efficient copy)
await Bun.write("./copy.txt", Bun.file("./original.txt"));
// Write with options
await Bun.write("./file.txt", "content", {
mode: 0o644, // Unix permissions
});
追加
// Using Bun.file writer
const file = Bun.file("./log.txt");
const writer = file.writer();
writer.write("Line 1\n");
writer.write("Line 2\n");
await writer.flush();
writer.end();
// Or use node:fs
import { appendFile } from "node:fs/promises";
await appendFile("./log.txt", "New line\n");
流式处理
读取流
const file = Bun.file("./large-file.txt");
const stream = file.stream();
const reader = stream.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
// Process chunk (Uint8Array)
console.log(value);
}
写入流
const file = Bun.file("./output.txt");
const writer = file.writer();
for await (const chunk of dataSource) {
writer.write(chunk);
}
await writer.end();
管道流
// File to file
const input = Bun.file("./input.txt");
const output = Bun.file("./output.txt");
await Bun.write(output, input);
// HTTP response to file
const response = await fetch(url);
await Bun.write("./download.zip", response);
// Process stream
const file = Bun.file("./data.txt");
const stream = file.stream();
const transformed = stream.pipeThrough(
new TransformStream({
transform(chunk, controller) {
// Process chunk
controller.enqueue(chunk.toUpperCase());
},
})
);
目录操作
import { readdir, mkdir, rmdir, stat } from "node:fs/promises";
import { existsSync, mkdirSync } from "node:fs";
// List directory
const files = await readdir("./src");
const filesWithTypes = await readdir("./src", { withFileTypes: true });
for (const entry of filesWithTypes) {
if (entry.isDirectory()) {
console.log(`Dir: ${entry.name}`);
} else if (entry.isFile()) {
console.log(`File: ${entry.name}`);
}
}
// Create directory
await mkdir("./new-dir", { recursive: true });
// Remove directory
await rmdir("./old-dir", { recursive: true });
// Check if exists
const exists = existsSync("./path");
Glob 模式
// Using Bun.Glob
const glob = new Bun.Glob("**/*.ts");
// Scan directory
for await (const file of glob.scan({ cwd: "./src" })) {
console.log(file); // Relative paths
}
// Get all matches
const files = await Array.fromAsync(glob.scan("./src"));
// With options
const glob2 = new Bun.Glob("**/*.{ts,tsx}");
for await (const file of glob2.scan({
cwd: "./src",
dot: true, // Include dotfiles
absolute: true, // Return absolute paths
onlyFiles: true, // Only files, not directories
})) {
console.log(file);
}
// Test if path matches
const pattern = new Bun.Glob("*.ts");
pattern.match("file.ts"); // true
pattern.match("file.js"); // false
文件元数据
import { stat, lstat } from "node:fs/promises";
const stats = await stat("./file.txt");
console.log(stats.size); // Size in bytes
console.log(stats.isFile()); // Is regular file
console.log(stats.isDirectory()); // Is directory
console.log(stats.isSymbolicLink()); // Is symlink
console.log(stats.mtime); // Modified time
console.log(stats.ctime); // Changed time
console.log(stats.atime); // Access time
console.log(stats.mode); // Permissions
路径操作
import { join, dirname, basename, extname, resolve } from "node:path";
const filePath = "/home/user/project/src/index.ts";
join("a", "b", "c"); // "a/b/c"
dirname(filePath); // "/home/user/project/src"
basename(filePath); // "index.ts"
basename(filePath, ".ts"); // "index"
extname(filePath); // ".ts"
resolve("./relative"); // Absolute path
// Bun-specific
import.meta.dir; // Directory of current file
import.meta.file; // Filename
import.meta.path; // Full path
常见模式
读取 JSON 配置
async function loadConfig<T>(path: string): Promise<T> {
const file = Bun.file(path);
if (!(await file.exists())) {
throw new Error(`Config not found: ${path}`);
}
return file.json();
}
const config = await loadConfig<AppConfig>("./config.json");
复制目录
import { readdir, mkdir, stat } from "node:fs/promises";
import { join } from "node:path";
async function copyDir(src: string, dest: string) {
await mkdir(dest, { recursive: true });
for (const entry of await readdir(src, { withFileTypes: true })) {
const srcPath = join(src, entry.name);
const destPath = join(dest, entry.name);
if (entry.isDirectory()) {
await copyDir(srcPath, destPath);
} else {
await Bun.write(destPath, Bun.file(srcPath));
}
}
}
监视文件
import { watch } from "node:fs";
watch("./src", { recursive: true }, (event, filename) => {
console.log(`${event}: ${filename}`);
});
// Or with Bun's built-in (faster)
const watcher = Bun.spawn(["bun", "--watch", "src/index.ts"]);
临时文件
import { mkdtemp } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
// Create temp directory
const tempDir = await mkdtemp(join(tmpdir(), "app-"));
console.log(tempDir); // /tmp/app-xxxxx
// Write temp file
const tempFile = join(tempDir, "data.txt");
await Bun.write(tempFile, "temporary data");
常见错误
| 错误 | 原因 | 修复方法 |
|---|---|---|
ENOENT | 找不到文件 | 检查路径,使用 exists() |
EACCES | 权限被拒绝 | 检查文件权限 |
EISDIR | 是一个目录 | 对目录使用 readdir() |
EEXIST | 已存在 | 创建目录时使用 recursive: true |
何时加载参考资料
在以下情况下加载 references/streams-advanced.md:
- 转换流
- 压缩流
- 二进制协议
在以下情况下加载 references/performance.md:
- 处理大型文件
- 内存优化
- 并发操作
评论
支持 Markdown