如何从S3图片流提取MIME类型并按类型命名写入磁盘?
解决方案:通过PassThrough流缓存数据,先获取格式再写入正确文件
你的核心问题在于:创建写入流时还没拿到图片格式,导致没法动态修改文件名。使用PassThrough流可以先缓存S3返回的图片数据,等拿到格式后再创建正确的写入流完成写入。
下面是修改后的完整代码:
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3"; import { createWriteStream } from "fs"; import { Readable, PassThrough } from "stream"; import sharp from "sharp"; async function retrieveAsset( bucket: string, asset: string, destination: string ) { const client = new S3Client({ region: "auto", endpoint: `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`, credentials: { accessKeyId: ACCESS_KEY_ID, secretAccessKey: SECRET_ACCESS_KEY, }, }); const response = await client.send( new GetObjectCommand({ Bucket: bucket, Key: asset }) ); const body = response.Body; if (!(body instanceof Readable)) { throw new Error("响应体不是可读流"); } // 1. 创建PassThrough流缓存图片数据,避免直接写入丢失 const passThrough = new PassThrough(); body.pipe(passThrough); // 2. 用sharp获取图片元数据,拿到格式信息 const meta = await sharp(passThrough).metadata(); if (!meta.format) { throw new Error("无法识别图片格式"); } // 3. 拼接最终文件名 const finalDestination = `${destination}.${meta.format}`; const writeStream = createWriteStream(finalDestination); // 4. 重置PassThrough流,重新导向到写入流 passThrough.unpipe(); passThrough.pipe(writeStream); // 5. 处理流的完成与错误事件 return new Promise((resolve, reject) => { writeStream.on("error", reject); writeStream.on("finish", resolve); passThrough.on("error", reject); }); }
关键逻辑说明
- PassThrough流的作用:作为数据缓存中间层,先接收S3返回的图片流,避免直接写入文件时还没拿到格式信息。
- 先获取格式再写入:通过
sharp().metadata()异步获取图片格式,拿到后再拼接正确的文件名,创建写入流。 - 重置流管道:因为sharp已经读取了PassThrough的部分数据,所以需要先解除之前的管道,重新将PassThrough导向新创建的写入流,确保所有数据都能写入文件。
调用示例:
retrieveAsset("test", "test.jpg", "newtest");
会生成文件newtest.jpg,完全符合你的需求。
内容的提问来源于stack exchange,提问作者pilotguy
相关产品推荐
相关产品推荐

