Bun

檔案 I/O

注意 — 本頁文件中記載的 Bun.fileBun.write API 經過深度優化,是執行 Bun 檔案系統任務的建議方式。對於 Bun.file 尚未提供的操作,例如 mkdirreaddir,您可以使用 Bun 幾乎完整的 幾乎完整node:fs 模組實作。

Bun 提供了一組優化的 API,用於讀取和寫入檔案。

讀取檔案 (Bun.file())

Bun.file(路徑): BunFile

使用 Bun.file(路徑) 函數建立 BunFile 實例。BunFile 代表延遲載入的檔案;初始化它實際上不會從磁碟讀取檔案。

const foo = Bun.file("foo.txt"); // relative to cwd
foo.size; // number of bytes
foo.type; // MIME type

此參考符合 Blob 介面,因此可以以各種格式讀取內容。

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

await foo.text(); // contents as a string
await foo.stream(); // contents as ReadableStream
await foo.arrayBuffer(); // contents as ArrayBuffer
await foo.bytes(); // contents as Uint8Array

檔案參考也可以使用數字 檔案描述符file:// URL 建立。

Bun.file(1234);
Bun.file(new URL(import.meta.url)); // reference to the current file

BunFile 可以指向磁碟上檔案不存在的位置。

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

預設的 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; // readonly
Bun.stdout;
Bun.stderr;

刪除檔案 (file.delete())

您可以透過呼叫 .delete() 函數來刪除檔案。

await Bun.file("logs.json").delete()

寫入檔案 (Bun.write())

Bun.write(目的地, 資料): Promise<number>

Bun.write 函數是一個多功能工具,用於將各種 payload 寫入磁碟。

第一個引數是 destination(目的地),它可以是以下任何類型

  • string:檔案系統上位置的路徑。使用 "path" 模組來操作路徑。
  • URLfile:// 描述符。
  • BunFile:檔案參考。

第二個引數是要寫入的資料。它可以是以下任何一種

  • 字串
  • Blob(包括 BunFile
  • ArrayBufferSharedArrayBuffer
  • TypedArrayUint8Array 等)
  • Response

所有可能的排列組合都使用當前平台上最快的可用系統呼叫來處理。

請參閱系統呼叫

將字串寫入磁碟

const data = `It was the best of times, it was the worst of times.`;
await Bun.write("output.txt", data);

將檔案複製到磁碟上的另一個位置

const input = Bun.file("input.txt");
const output = Bun.file("output.txt"); // doesn't exist yet!
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.dev.org.tw");
await Bun.write("index.html", response);

使用 FileSink 進行增量寫入

Bun 提供了一個稱為 FileSink 的原生增量檔案寫入 API。若要從 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("it was the best of times\n");
writer.write("it was the worst of times\n");

這些區塊將在內部緩衝。若要將緩衝區刷新到磁碟,請使用 .flush()。這會傳回刷新的位元組數。

writer.flush(); // write buffer to disk

當達到 FileSink 的 *高水位線* 時,緩衝區也會自動刷新;也就是說,當其內部緩衝區已滿時。此值可以設定。

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

若要刷新緩衝區並關閉檔案

writer.end();

請注意,預設情況下,bun 程序將保持運作,直到使用 .end() 明確關閉此 FileSink 為止。若要選擇退出此行為,您可以「取消引用」實例。

writer.unref();

// to "re-ref" it later
writer.ref();

目錄

Bun 的 node:fs 實作速度很快,而且我們尚未實作 Bun 特定的 API 來讀取目錄。目前,您應該使用 node:fs 在 Bun 中處理目錄。

讀取目錄 (readdir)

若要在 Bun 中讀取目錄,請使用 node:fs 中的 readdir

import { readdir } from "node:fs/promises";

// read all the files in the current directory
const files = await readdir(import.meta.dir);

遞迴讀取目錄

若要在 Bun 中遞迴讀取目錄,請將 readdirrecursive: true 一起使用。

import { readdir } from "node:fs/promises";

// read all the files in the current directory, recursively
const files = await readdir("../", { recursive: true });

建立目錄 (mkdir)

若要遞迴建立目錄,請使用 node:fs 中的 mkdir

import { mkdir } from "node:fs/promises";

await mkdir("path/to/dir", { recursive: true });

基準測試

以下是 Linux cat 命令的 3 行實作。

cat.ts
// Usage
// $ 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(): ReadableStream;
  arrayBuffer(): Promise<ArrayBuffer>;
  json(): Promise<any>;
  writer(params: { highWaterMark?: number }): FileSink;
  exists(): Promise<boolean>;
}

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;
}