
作為一名 AWS 的忠實用戶,使用 s3 存放檔案是日常常見的事情
以往如果要用 nodejs 就要用 aws-sdk 去實現相關行為,bun 基本上有內建的
s3 client 達成一些 aws-sdk 可以做到的任務,最主要的事我這篇擺在這正好呼應上一篇BunFile 相關的操作,這兩者是有關係的,也是可以展現出 bun 的威能
首先我們要有一個 AWS 帳號(如果讀者有想學習如何做的話記得去註冊一個)
有了 AWS 帳號後,我們就可以用 s3 的服務
S3 大家可以想像像是 Google drive 或 dropbox 等等簡言之就是一個雲端的存儲空間,
這好處是這個存儲空間成本不高,且會依照每 GB 的量計費,不像 Google drive 會依照方案的不同
會有有限的存儲大小
串接 s3 前,我們可以在 AWS 進入畫面找到 access Key, access secret, access token(可以參考圖片)



有鑑於此我們這裡先設定環境變數 .env 去拿取這些資訊
S3_ACCESS_KEY_ID=<你的 ACCESSKEY>
S3_SECRET_ACCESS_KEY=<你的 ACCESSSECRET>
S3_SESSION_TOKEN=<你的 Session token>
S3_BUCKET=<你的 bucket 名稱 >
S3_REGION=<你的 region 代碼>
我們先把 .env 放在我的的專案裡面
index.ts 開始執行import { S3Client } from 'bun';
const accessKeyId = process.env.S3_ACCESS_KEY_ID ?? '';
const secretAccessKey = process.env.S3_SECRET_ACCESS_KEY ?? '';
const sessionToken = process.env.S3_SESSION_TOKEN ?? '';
const bucket = process.env.S3_BUCKET ?? '';
const region = process.env.S3_REGION ?? '';
if (accessKeyId === '' || secretAccessKey === '' || sessionToken === '' || bucket === '' || region === '') {
throw new Error('沒有抓到 credential 相關資料');
}
const s3 = new S3Client({
accessKeyId,
secretAccessKey,
sessionToken,
bucket,
region
});
console.log(s3);
我們可以執行看看結果,看是否有成功能到我們要的資訊

const simpleUploadFile = async (s3: S3Client): Promise<void> => {
await s3.write('hello.txt', '這是一隻貓');
await s3.write('data.json', JSON.stringify({ name: '這是一隻json酷貓' }))
}
await simpleUploadFile(s3);


補充 : 如果需要上傳本地的就不用加第二個參數(程式碼如下)
const simpleUploadLoadFile = async (s3: S3Client): Promise<void> => {
await s3.write('./sample.png');
}
await simpleUploadFile(s3);
如果檔案太大的話這裡可以用 multiPart/file chunking 的方式處理
const uploadLargeFile = async (s3: S3Client): Promise<void> => {
const file = s3.file('large-file-sample.zip', {
partSize: 10 * 1024 * 1024, // 這裡我們分每 10MB 的間隔
queueSize: 4, // 平行處理 4 個 part
});
const writer = file.writer();
const source = Bun.file('./large-file-sample.zip').stream();
for await (const chunk of source) {
writer.write(chunk);
}
await writer.end();
}


一樣我們這裡會示範如何簡單的下載,和處理大檔案時如何下載
const simpleDownload = async (s3: S3Client): Promise<void> => {
const file = s3.file('hello.txt');
// 我們直接寫到硬碟裡
await Bun.write('./hello.txt', file);
}

const largFileDownload = async (s3: S3Client): Promise<void> => {
const file = s3.file('large-file-sample.zip')
const stream = file.stream();
const target = Bun.file('./sample.zip');
const writer = target.writer();
for await (const chunk of stream) {
writer.write(chunk);
}
await writer.end();
}

從今天的介紹可以看到,Bun 的 S3Client 其實延續了昨天 BunFile 的設計哲學——無論是本地檔案還是雲端物件儲存,
都可以用同一套 stream()、writer() API 來操作,這也是 Bun 想要打造「統一檔案介面」的野心。
不用再為了串接 S3 而額外安裝笨重的 aws-sdk,光是內建功能就能應付日常九成的需求。
不過,你可能會好奇:如果不是 AWS S3,而是 Cloudflare R2、MinIO 這種 S3 相容服務,
Bun 的 S3Client 還能無縫接軌嗎?其實是可以的,不過因為篇幅有限,目前先埋個伏筆在這,有機會的話再更近一步深入討論
iThome鐵人賽