文件存储
Use persistent and ephemeral file storage
Edge Functions 提供两种文件存储方式:
🌐 Edge Functions provides two flavors of file storage:
- 持久 - 支持 S3 协议,可以从任何兼容 S3 的存储桶读写,包括 Supabase Storage
- 短暂 - 你可以读写
/tmp目录下的文件。只适合临时操作
你可以使用文件存储来:
🌐 You can use file storage to:
- 处理复杂的文件转换和工作流程
- 在项目之间进行数据迁移
- 处理用户上传的文件并保存它们
- 解压档案并处理内容后再保存到数据库
持久存储 #
🌐 Persistent Storage
持久存储选项是建立在 S3 协议之上的。它允许你将任何兼容 S3 的存储桶,包括 Supabase 存储桶,挂载为 Edge Functions 的目录。你可以像在 POSIX 文件系统中一样,对挂载的存储桶进行读取和写入文件的操作。
🌐 The persistent storage option is built on top of the S3 protocol. It allows you to mount any S3-compatible bucket, including Supabase Storage Buckets, as a directory for your Edge Functions. You can perform operations such as reading and writing files to the mounted buckets as you would in a POSIX file system.
要从 Edge Functions 访问 S3 存储桶,你必须在 Edge Function Secrets 中为环境变量设置以下内容。
🌐 To access an S3 bucket from Edge Functions, you must set the following for environment variables in Edge Function Secrets.
S3FS_ENDPOINT_URLS3FS_REGIONS3FS_ACCESS_KEY_IDS3FS_SECRET_ACCESS_KEY
按照此指南 启用并为 Supabase Storage S3 创建访问密钥。
要从你的 Edge Function 访问已挂载桶中的文件路径,请使用前缀 /s3/YOUR-BUCKET-NAME。
🌐 To access a file path in your mounted bucket from your Edge Function, use the prefix /s3/YOUR-BUCKET-NAME.
1// read from S3 bucket2const data = await Deno.readFile('/s3/my-bucket/results.csv')34// make a directory5await Deno.mkdir('/s3/my-bucket/sub-dir')67// write to S3 bucket8await Deno.writeTextFile('/s3/my-bucket/demo.txt', 'hello world')临时存储 #
🌐 Ephemeral storage
临时存储在每次函数调用时都会重置。这意味着你在一次调用中写入的文件只能在同一次调用中读取。
🌐 Ephemeral storage will reset on each function invocation. This means the files you write during an invocation can only be read within the same invocation.
你可以使用 Deno 文件系统 API 或 node:fs 模块来访问 /tmp 路径。
🌐 You can use Deno File System APIs or the node:fs module to access the /tmp path.
1Deno.serve(async (req) => {2 if (req.headers.get('content-type') !== 'application/zip') {3 return new Response('file must be a zip file', {4 status: 400,5 })6 }78 const uploadId = crypto.randomUUID()9 await Deno.writeFile('/tmp/' + uploadId, req.body)1011 // E.g. extract and process the zip file12 const zipFile = await Deno.readFile('/tmp/' + uploadId)13 // You could use a zip library to extract contents14 const extracted = await extractZip(zipFile)1516 // Or process the file directly17 console.log(`Processing zip file: ${uploadId}, size: ${zipFile.length} bytes`)18})常见用例 #
🌐 Common use cases
使用后台任务处理归档 #
🌐 Archive processing with background tasks
你可以使用临时存储和 后台任务 来处理超过内存限制的大文件处理操作。
🌐 You can use ephemeral storage with Background Tasks to handle large file processing operations that exceed memory limits.
想象一下,你有一个照片相册应用,它接受以 zip 文件形式上传的照片。使用流式实现的话,当 zip 文件超过 100MB 时会遇到内存限制错误,因为它会把所有归档文件同时保存在内存中。
🌐 Imagine you have a Photo Album application that accepts photo uploads as zip files. A streaming implementation will run into memory limit errors with zip files exceeding 100MB, as it retains all archive files in memory simultaneously.
你可以先把 zip 文件写入临时存储,然后用后台任务提取并上传文件到 Supabase 存储。这样,你只需要将 zip 文件的部分内容读入内存。
🌐 You can write the zip file to ephemeral storage first, then use a background task to extract and upload files to Supabase Storage. This way, you only read parts of the zip file to the memory.
1import { BlobWriter, ZipReader } from 'https://deno.land/x/zipjs/index.js'2import { createClient } from 'jsr:@supabase/supabase-js@2'34const SUPABASE_SECRET_KEYS = JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!)5// If you want to use a different api key, change 'default' to your preferred key name6const supabase = createClient(Deno.env.get('SUPABASE_URL')!, SUPABASE_SECRET_KEYS['default'])78async function processZipFile(uploadId: string, filepath: string) {9 const file = await Deno.open(filepath, { read: true })10 const zipReader = new ZipReader(file.readable)11 const entries = await zipReader.getEntries()1213 await supabase.storage.createBucket(uploadId, { public: false })1415 await Promise.all(16 entries.map(async (entry) => {17 if (entry.directory) return1819 // Read file entry from temp storage20 const blobWriter = new BlobWriter()21 const blob = await entry.getData(blobWriter)2223 // Upload to permanent storage24 await supabase.storage.from(uploadId).upload(entry.filename, blob)2526 console.log('uploaded', entry.filename)27 })28 )2930 await zipReader.close()31}3233Deno.serve(async (req) => {34 const uploadId = crypto.randomUUID()35 const filepath = `/tmp/${uploadId}.zip`3637 // Write zip to ephemeral storage38 await Deno.writeFile(filepath, req.body)3940 // Process in background to avoid memory limits41 EdgeRuntime.waitUntil(processZipFile(uploadId, filepath))4243 return new Response(JSON.stringify({ uploadId }), {44 headers: { 'Content-Type': 'application/json' },45 })46})图片处理 #
🌐 Image manipulation
使用 magick-wasm 的自定义图片处理工作流程。
🌐 Custom image manipulation workflows using magick-wasm.
1Deno.serve(async (req) => {2 // Save uploaded image to temp storage3 const imagePath = `/tmp/input-${crypto.randomUUID()}.jpg`4 await Deno.writeFile(imagePath, req.body)56 // Process image with magick-wasm7 const processedPath = `/tmp/output-${crypto.randomUUID()}.jpg`8 // ... image manipulation logic910 // Read processed image and return11 const processedImage = await Deno.readFile(processedPath)12 return new Response(processedImage, {13 headers: { 'Content-Type': 'image/jpeg' },14 })15})使用同步文件 API #
🌐 Using synchronous file APIs
你可以在初始脚本评估期间安全地使用以下同步 Deno API(以及它们的 Node 对应 API):
🌐 You can safely use the following synchronous Deno APIs (and their Node counterparts) during initial script evaluation:
- Deno.statSync
- Deno.removeSync
- Deno.writeFileSync
- Deno.writeTextFileSync
- Deno.readFileSync
- Deno.readTextFileSync
- Deno.mkdirSync
- Deno.makeTempDirSync
- Deno.readDirSync
记住,同步 API 只在初始脚本评估时可用,并且不支持在回调中使用,例如 HTTP 处理器或 setTimeout。
1Deno.statSync('...') // ✅23setTimeout(() => {4 Deno.statSync('...') // 💣 ERROR! Deno.statSync is blocklisted on the current context5})67Deno.serve(() => {8 Deno.statSync('...') // 💣 ERROR! Deno.statSync is blocklisted on the current context9})限制 #
🌐 Limits
你挂载用于持久存储的 S3 桶没有数量限制。
🌐 There are no limits on S3 buckets you mount for Persistent storage.
临时存储:
🌐 Ephemeral Storage:
- 免费项目:最多 256MB 临时存储
- 付费项目:最多512MB的临时存储