【Bun中文文档-API】File I/O

814 阅读4分钟

注意 — 此页面记录的Bun.fileBun.write API 经过了大量优化,代表了使用 Bun 执行文件系统任务的推荐方式。对于尚不可用于Bun.file的操作,例如mkdirreaddir,您可以使用 Bun 的几乎完整的 node:fs 模块实现。

Bun 提供了一组优化的 API,用于读取和写入文件。

读取文件(Bun.file()

Bun.file(path): BunFile

使用Bun.file(path)函数创建一个BunFile实例。BunFile表示一种懒加载的文件;初始化它实际上不会从磁盘读取文件。

const foo = Bun.file("foo.txt"); // 相对于cwd
foo.size; // 字节数
foo.type; // MIME类型

该引用符合Blob接口,因此可以以不同的格式读取内容。

const foo = Bun.file("foo.txt");

await foo.text(); // 作为字符串的内容
await foo.stream(); // 作为ReadableStream的内容
await foo.arrayBuffer(); // 作为ArrayBuffer的内容

文件引用还可以使用数字file descriptorsfile:// URL 创建。

Bun.file(1234);
Bun.file(new URL(import.meta.url)); // 对当前文件的引用

BunFile可以指向磁盘上不存在文件的位置。

const notreal = Bun.file("notreal.txt");
notreal.size; // 0
notreal.type; // "text/plain;charset=utf-8"

默认的 MIME 类型是text/plain;charset=utf-8,但可以通过向Bun.file传递第二个参数来覆盖它。

const notreal = Bun.file("notreal.json", { type: "application/json" });
notreal.type; // => "application/json;charset=utf-8"

为方便起见,Bun 将stdinstdoutstderr公开为BunFile的实例。

Bun.stdin; // 只读
Bun.stdout;
Bun.stderr;

写入文件(Bun.write()

Bun.write(destination, data): Promise<number>

Bun.write函数是一个多用途工具,用于将各种类型的数据写入磁盘。

第一个参数是destination,可以是以下任何类型:

  • string:文件系统上的位置路径。使用"path"模块来操作路径。
  • URL:一个file://描述符。
  • BunFile:文件引用。

第二个参数是要写入的数据,可以是以下任何类型:

  • string
  • Blob(包括BunFile
  • ArrayBufferSharedArrayBuffer
  • TypedArray(例如Uint8Array等)
  • Response

所有可能的排列组合都使用当前平台上最快速的可用系统调用来处理。

查看系统调用
输出输入系统调用平台
文件文件copy_file_rangeLinux
文件管道sendfileLinux
管道管道spliceLinux
终端文件sendfileLinux
终端终端sendfileLinux
套接字文件或管道sendfile(如果是 http 而不是 https)Linux
文件(不存在)文件(路径)clonefilemacOS
文件(存在)文件fcopyfilemacOS
文件Blob 或字符串writemacOS
文件Blob 或字符串writeLinux

要将字符串写入磁盘:

const data = `这是最好的时光,也是最坏的时光。`;
await Bun.write("output.txt", data);

要将文件复制到磁盘上的另一个位置:

const input = Bun.file("input.txt");
const output = Bun.file("output.txt"); // 尚不存在!
await Bun.write(output, input);

要将字节数组写入磁盘:

const encoder = new TextEncoder();
const data = encoder.encode("datadatadata"); // Uint8Array
await Bun.write("output.txt", data);

要将文件写入stdout

const input = Bun.file("input.txt");
await Bun.write(Bun.stdout, input);

要将 HTTP 响应的主体写入磁盘:

const response = await fetch("https://bun.sh");
await Bun.write("index.html", response);

使用FileSink进行增量写入

Bun 提供了一个本地的增量文件写入 API,称为FileSink。要从BunFile检索FileSink实例:

const file = Bun.file("output.txt");
const writer = file.writer();

要逐步写入文件,请调用.write()

const file = Bun.file("output.txt");
const writer = file.writer();

writer.write("这是最好的时光\n");
writer.write("这是最坏的时光\n");

这些块将在内部进行缓冲。要将缓冲区刷新到磁盘上,请使用.flush()。这将返回已刷新的字节数。

writer.flush(); // 将缓冲区写入磁盘

FileSink高水位标记达到时,即其内部缓冲区已满时,缓冲区也会自动刷新。这个值可以配置。

const file = Bun.file("output.txt");
const writer = file.writer({ highWaterMark: 1024 * 1024 }); // 1MB

要刷新缓冲区并关闭文件:

writer.end();

请注意,默认情况下,bun进程将保持活动状态,直到使用.end()显式关闭此FileSink。要退出此行为,您可以对实例进行"unref"操作。

writer.unref();

// 以后要重新引用它
writer.ref();

基准测试

以下是 Linux cat命令的 3 行实现。

// 用法
// $ bun ./cat.ts ./path-to-file

import { resolve } from "path";

const path = resolve(process.argv.at(-1));
await Bun.write(Bun.stdout, Bun.file(path));

要运行文件:

$ bun ./cat.ts ./path-to-file

对于 Linux 上的大文件,它比 GNU cat运行快 2 倍。

图片转存失败,建议将图片保存下来直接上传

参考

interface Bun {
  stdin: BunFile;
  stdout: BunFile;
  stderr: BunFile;

  file(path: string | number | URL, options?: { type?: string }): BunFile;

  write(
    destination: string | number | BunFile | URL,
    input:
      | string
      | Blob
      | ArrayBuffer
      | SharedArrayBuffer
      | TypedArray
      | Response
  ): Promise<number>;
}

interface BunFile {
  readonly size: number;
  readonly type: string;

  text(): Promise<string>;
  stream(): Promise<ReadableStream>;
  arrayBuffer(): Promise<ArrayBuffer>;
  json(): Promise<any>;
  writer(params: { highWaterMark?: number }): FileSink;
}

export interface FileSink {
  write(
    chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer
  ): number;
  flush(): number | Promise<number>;
  end(error?: Error): number | Promise<number>;
  start(options?: { highWaterMark?: number }): void;
  ref(): void;
  unref(): void;
}