iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0

title_s3_iamge

前言

作為一名 AWS 的忠實用戶,使用 s3 存放檔案是日常常見的事情
以往如果要用 nodejs 就要用 aws-sdk 去實現相關行為,bun 基本上有內建的
s3 client 達成一些 aws-sdk 可以做到的任務,最主要的事我這篇擺在這正好呼應上一篇
BunFile 相關的操作,這兩者是有關係的,也是可以展現出 bun 的威能

如何使用

首先我們要有一個 AWS 帳號(如果讀者有想學習如何做的話記得去註冊一個)
有了 AWS 帳號後,我們就可以用 s3 的服務

什麼是 s3 (簡單介紹)

S3 大家可以想像像是 Google drive 或 dropbox 等等簡言之就是一個雲端的存儲空間,
這好處是這個存儲空間成本不高,且會依照每 GB 的量計費,不像 Google drive 會依照方案的不同
會有有限的存儲大小

串接 s3

串接 s3 前,我們可以在 AWS 進入畫面找到 access Key, access secret, access token(可以參考圖片)

aws1
aws2
aws3

有鑑於此我們這裡先設定環境變數 .env 去拿取這些資訊

.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);

我們可以執行看看結果,看是否有成功能到我們要的資訊

resulit

上傳檔案

簡單上傳

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

await simpleUploadFile(s3);

upload_1
upload2

補充 : 如果需要上傳本地的就不用加第二個參數(程式碼如下)

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

uplload_large
upload_large_result

檔案下載

一樣我們這裡會示範如何簡單的下載,和處理大檔案時如何下載

簡易下載

const simpleDownload = async (s3: S3Client): Promise<void> => {
  const file = s3.file('hello.txt');
  // 我們直接寫到硬碟裡
  await Bun.write('./hello.txt', file);
}

simple download

大檔案下載

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

large download

結論

從今天的介紹可以看到,Bun 的 S3Client 其實延續了昨天 BunFile 的設計哲學——無論是本地檔案還是雲端物件儲存,
都可以用同一套 stream()writer() API 來操作,這也是 Bun 想要打造「統一檔案介面」的野心。

不用再為了串接 S3 而額外安裝笨重的 aws-sdk,光是內建功能就能應付日常九成的需求。
不過,你可能會好奇:如果不是 AWS S3,而是 Cloudflare R2、MinIO 這種 S3 相容服務,
Bun 的 S3Client 還能無縫接軌嗎?其實是可以的,不過因為篇幅有限,目前先埋個伏筆在這,有機會的話再更近一步深入討論


上一篇
Bun File I/O:讀寫檔案比 Node.js fs 更直覺
系列文
不只是快 —— Bun 30 天:從底層架構、全套工具鏈到生產部署10
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言