執行環境套件管理器打包器測試執行器程式碼檢查格式化指南參考部落格意見回饋

檔案 I/O

Bun 提供了一組經過最佳化的 API 用於讀取和寫入檔案。


讀取檔案 (Bun.file())

Bun.file(path): BunFile

使用 Bun.file(path) 函式建立一個 BunFile 例項。BunFile 表示一個延遲載入的檔案;初始化它不會從磁碟讀取檔案。

TypeScript
const foo = Bun.file("foo.txt"); // 相對於當前工作目錄
foo.size; // 位元組數
foo.type; // MIME 型別

該引用符合 Blob 介面,因此你可以使用多種格式讀取內容。

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

await foo.text(); // 內容作為字串
await foo.json(); // 內容作為 JSON 物件
foo.stream(); // 內容作為 ReadableStream
await foo.arrayBuffer(); // 內容作為 ArrayBuffer
await foo.bytes(); // 內容作為 Uint8Array

你也可以從數字形式的檔案描述符或 file:// URL 建立檔案引用。

TypeScript
Bun.file(1234);
Bun.file(new URL(import.meta.url)); // 當前檔案的引用

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

TypeScript
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 傳入第二個引數可以覆蓋該型別。

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

為了方便,Bun 將 stdin、stdout 和 stderr 作為 BunFile 例項暴露。

TypeScript
Bun.stdin; // 只讀
Bun.stdout;
Bun.stderr;

刪除檔案 (file.delete())

呼叫 .delete() 刪除檔案。

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

寫入檔案 (Bun.write())

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

Bun.write 是一個多功能工具,用於將各種型別的負載寫入磁碟。

第一個引數是 destination,可以是以下任意型別:

  • string:檔案系統上的路徑。使用 "path" 模組進行路徑操作。
  • URL:file:// 描述符。
  • BunFile:檔案引用。

第二個引數是要寫入的資料,可以是以下任意型別:

  • string
  • Blob(包括 BunFile)
  • ArrayBuffer 或 SharedArrayBuffer
  • TypedArray(如 Uint8Array 等)
  • Response

Bun 會針對每種組合,使用當前平臺上可用的最快系統呼叫。

檢視系統呼叫
輸出輸入系統呼叫平臺
檔案檔案copy_file_rangeLinux
檔案管道sendfileLinux
管道管道spliceLinux
終端檔案sendfileLinux
終端終端sendfileLinux
套接字檔案或管道sendfile(如果是 http,則不是 https)Linux
檔案(不存在)檔案(路徑)clonefilemacOS
檔案(已存在)檔案fcopyfilemacOS
檔案Blob 或字串writemacOS
檔案Blob 或字串writeLinux

將字串寫入磁碟:

TypeScript
const data = `那是最好的時代,那是最壞的時代。`;
await Bun.write("output.txt", data);

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

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

將位元組陣列寫入磁碟:

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

將檔案內容寫入 stdout:

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

將 HTTP 響應的正文寫入磁碟:

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

使用 FileSink 進行增量寫入

Bun 提供了一個原生的增量寫入檔案 API,叫做 FileSink。從 BunFile 獲取 FileSink 例項:

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

增量寫入檔案時,呼叫 .write()。

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

writer.write("那是最好的時代\n");
writer.write("那是最壞的時代\n");

FileSink 會在內部緩衝這些資料塊。要將緩衝區重新整理到磁碟,請使用 .flush()。它會傳回已重新整理的位元組數。

TypeScript
writer.flush(); // 將快取寫入磁碟

當 FileSink 達到其_高水位標記_時,緩衝區也會自動重新整理;也就是說,當其內部緩衝區已滿時會自動重新整理。你可以設定此值。

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

重新整理快取並關閉檔案:

TypeScript
writer.end();

預設情況下,bun 行程會保持執行,直到你使用 .end() 顯式關閉此 FileSink。要選擇不採用此行為,請對例項呼叫 "unref"。

TypeScript
writer.unref();

// 之後可再次呼叫以恢復保持行程存活
writer.ref();

目錄操作

Bun 對 node:fs 的實現速度很快。在 Bun 中使用 node:fs 處理目錄。

讀取目錄(readdir)

在 Bun 中,使用 node:fs 模組的 readdir 讀取目錄。

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

// 讀取當前目錄下所有檔案
const files = await readdir(import.meta.dir);

遞迴讀取目錄

使用 readdir 並開啟 recursive: true 遞迴讀取目錄。

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

// 遞迴讀取上級目錄中所有檔案
const files = await readdir("../", { recursive: true });

建立目錄(mkdir)

遞迴建立目錄需使用 node:fs 的 mkdir:

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

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

效能基準

以下是 Linux 下 cat 命令的三行實現。

cat.ts
// 用法
// 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));

執行該檔案:

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

在 Linux 上處理大檔案時,速度是 GNU cat 的 2 倍。

貓截圖

參考

TypeScript
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>;
  bytes(): Promise<Uint8Array>;
  writer(params?: { highWaterMark?: number }): FileSink;
  exists(): Promise<boolean>;
  delete(): Promise<void>;
}

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