Chapter 05

内置 API:文件、SQLite、Redis 等

Bun 把许多"常见业务刚需"直接内置成零依赖 API——读写文件、本地数据库、密码哈希、子进程。

5.1 Bun.file / Bun.write:文件 IO

// 读文件(惰性,调用 .text() 才真读)
const f = Bun.file("./package.json");
const text = await f.text();
const json = await f.json();
const bytes = await f.arrayBuffer();
console.log(f.size, f.type);

// Bun.file 返回的 BunFile 对象符合 Blob 接口
return new Response(Bun.file("./photo.jpg"));   // 直接作为 HTTP body

// 写文件
await Bun.write("./out.txt", "hello");
await Bun.write("./out.json", { name: "bun" });    // 自动 JSON.stringify
await Bun.write("./copy.jpg", Bun.file("./photo.jpg"));  // 文件到文件复制
await Bun.write("./out.bin", new Uint8Array([1, 2, 3]));
为什么比 fs.readFile 快?

Bun.file 返回的是惰性文件句柄——元数据(size/type)即时可得,但真实读取推迟到你调用 .text() 等方法时。内部用了 Zig 的零拷贝 IO 和 sendfile 系统调用,比 fs.readFile 快 10-20 倍。

5.2 fs API(Node 兼容)

如果你习惯 import fs from "node:fs",一样能用——Bun 把 node:fs 也实现了:

import { readFile, writeFile } from "node:fs/promises";
const text = await readFile("package.json", "utf8");

新代码推荐用 Bun.file,旧代码原样迁过来也能跑。

5.3 bun:sqlite:内置 SQLite

本地数据库零依赖,性能比 better-sqlite3 还快:

import { Database } from "bun:sqlite";

const db = new Database("mydb.sqlite");

db.run(`
  CREATE TABLE IF NOT EXISTS users (
    id   INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    age  INTEGER
  )
`);

// 预编译语句(推荐,防 SQL 注入)
const insert = db.prepare("INSERT INTO users (name, age) VALUES ($name, $age)");
insert.run({ $name: "Alice", $age: 30 });

const query = db.query("SELECT * FROM users WHERE age > $min");
const rows = query.all({ $min: 18 });

// as-object 返回类型
interface User { id: number; name: string; age: number; }
const users = db.query("SELECT * FROM users").as(User).all();

事务

const insertMany = db.transaction((users) => {
  for (const u of users) insert.run(u);
});
insertMany([
  { $name: "Bob", $age: 25 },
  { $name: "Carol", $age: 40 },
]);

5.4 bun:redis(Bun 1.2+)

import { redis } from "bun";

await redis.set("greeting", "hello");
const v = await redis.get("greeting");

await redis.hset("user:1", { name: "Alice", age: "30" });
const user = await redis.hgetall("user:1");

await redis.expire("greeting", 60);

默认连接 redis://localhost:6379,通过 REDIS_URL 环境变量或 new RedisClient(url) 自定义。

5.5 Bun.password:密码哈希

Argon2id(默认,现代标准)/ bcrypt,免装 bcrypt 包:

const hash = await Bun.password.hash("mySecret123");
// $argon2id$v=19$m=65536,t=2,p=1$...

const ok = await Bun.password.verify("mySecret123", hash);

// 想要 bcrypt?
const h2 = await Bun.password.hash("x", { algorithm: "bcrypt", cost: 10 });

5.6 Bun.spawn:子进程

const proc = Bun.spawn(["ls", "-la"], {
  cwd: "./",
  env: { ...process.env, DEBUG: "1" },
  stdout: "pipe",
});
const text = await new Response(proc.stdout).text();
await proc.exited;
console.log(text, proc.exitCode);

// 同步版 spawnSync
const r = Bun.spawnSync(["git", "rev-parse", "HEAD"]);
console.log(r.stdout.toString());

5.7 Bun.hash / Bun.CryptoHasher

// 快速哈希(非加密,散列表场景)
Bun.hash("hello");                  // Wyhash(默认)
Bun.hash.crc32("hello");

// 加密哈希
const hasher = new Bun.CryptoHasher("sha256");
hasher.update("hello");
const digest = hasher.digest("hex");

5.8 Bun.S3Client(S3 原生)

import { S3Client } from "bun";

const s3 = new S3Client({
  accessKeyId: process.env.AWS_ACCESS_KEY_ID,
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
  bucket: "my-bucket",
  region: "us-east-1",
});

await s3.write("hello.txt", "world");
const body = await s3.file("hello.txt").text();
const url = s3.presign("hello.txt", { expiresIn: 3600 });

5.9 Bun.sleep / Bun.inspect / Bun.env

await Bun.sleep(100);                // 异步等待 100ms
Bun.sleepSync(100);                  // 同步阻塞(慎用)

Bun.inspect(obj);                   // 类似 util.inspect
Bun.deepEquals(a, b);                // 深比较

Bun.env.DATABASE_URL;                // 等同 process.env

5.10 小结