如何使用 MinIO 的 S3 ZIP 扩展直接列出并下载 ZIP 对象内的文件?
【免费下载链接】minioMinIO is a high-performance, S3 compatible object store, open sourced under GNU AGPLv3 license.项目地址: https://gitcode.com/GitHub_Trending/mi/minio
当一个 ZIP 归档已经作为普通 S3 对象上传到 MinIO 的某个 bucket 时,MinIO 的 S3 ZIP 扩展允许你用常规 S3 API 直接列出归档内的文件、并下载其中指定的单个文件,而不必先下载整个 ZIP 再解压。启用方式只有一个:在请求中附加x-minio-extract为true的 header,并在请求路径上把归档内路径拼接到归档对象的 key 之后。仓库自带 S3 ZIP 扩展说明 和三个语言的完整示例(boto3、minio-go、AWS JS SDK v2),本文以这些示例为操作路径,说明"列出"和"下载"两个动作怎么做、以及如何判断结果。
启用方式与请求路径规则
完成本场景需要遵循的协议约定(来自 docs/extensions/s3zip/README.md):
- 在 S3 请求上设置 header:
x-minio-extract值为true。 - 访问归档内部内容时,把归档内路径直接追加到归档对象 key 之后。文档给出的例子:要下载存储在 bucket
company-data的financial.zip内的2021/taxes.csv,发起 GET 请求使用的路径为company-data/financial.zip/2021/taxes.csv。 - 该扩展仅适用于对 ZIP 内文件的以下读操作:
HeadObject、GetObject、ListObjectsV2。 - 边界限制:要更新或删除 ZIP 内某个文件的内容,必须整体替换 ZIP 文件。
准备条件
- 一个可访问的 MinIO 服务。三个示例中使用的 endpoint 分别为
http://localhost:9000(boto3)、http://127.0.0.1:9000(JS)、minio-server-address:9000(Go,占位符),按实际部署地址替换。 - 可用的访问凭证。示例中的
YOUR-ACCESSKEYID/YOUR-SECRETACCESSKEY、access-key/secret-key均为占位符,需替换为你自己的 AccessKey 和 SecretKey。 - 客户端 SDK 需要能够设置自定义 HTTP header。仓库示例分别依赖 boto3(AWS SDK for Python)、
github.com/minio/minio-go/v7、aws-sdk(JS,见 package.json 中声明的aws-sdk ^2.924.0)。
示例代码位于 examples 目录,下文路径均相对仓库根目录。
列出 ZIP 内的文件(boto3 主路径)
docs/extensions/s3zip/examples/boto3/main.py 同时覆盖了列出与下载,是最完整的参考。完整示例如下:
#!/usr/bin/env/python import boto3 from botocore.client import Config s3 = boto3.client('s3', endpoint_url='http://localhost:9000', aws_access_key_id='YOUR-ACCESSKEYID', aws_secret_access_key='YOUR-SECRETACCESSKEY', config=Config(signature_version='s3v4'), region_name='us-east-1') def _add_header(request, **kwargs): request.headers.add_header('x-minio-extract', 'true') event_system = s3.meta.events event_system.register_first('before-sign.s3.*', _add_header) # List zip contents response = s3.list_objects_v2(Bucket="your-bucket", Prefix="path/to/file.zip/") print(response) # Download data.csv stored in the zip file s3.download_file(Bucket='your-bucket', Key='path/to/file.zip/data.csv', Filename='/tmp/data.csv')示例中需要替换的值:
endpoint_url:MinIO 服务地址,示例为http://localhost:9000;YOUR-ACCESSKEYID/YOUR-SECRETACCESSKEY:你的访问凭证;your-bucket:存放 ZIP 归档的 bucket 名;path/to/file.zip/:归档对象的 key 后加/,作为Prefix;path/to/file.zip/data.csv:归档 key 后接归档内目标文件的相对路径。
两点需要注意:
- 文档明确要求使用ListObjectsV2来列出 ZIP 内容,示例中的
list_objects_v2与该要求一致,不要换成 ListObjectsV1。 - header 是通过
event_system.register_first('before-sign.s3.*', _add_header)注册到事件系统上的,对该 client 之后的 S3 请求(包括随后的download_file)统一生效,因此下载调用本身不需要再单独设置 header。
下载 ZIP 内的单个文件
下载就是普通的GetObject,只是对象 key 写成"归档 key + 归档内路径"。上述示例最后一行s3.download_file(Bucket='your-bucket', Key='path/to/file.zip/data.csv', Filename='/tmp/data.csv')会把 ZIP 内的data.csv直接写到/tmp/data.csv。如果你只需要读取内容而不落盘,Go 示例展示的是把对象内容输出到 stdout 的写法(见下一节)。
替代 SDK:minio-go 与 AWS JS SDK v2(可选分支)
如果你使用 Go 或 Node.js 客户端,按 minio-go 示例 和 AWS JS 示例 设置 header 即可。
minio-go(注意minio-server-address是占位符,access-key/secret-key需替换为真实凭证):
package main import ( "context" "io" "log" "os" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" ) func main() { s3Client, err := minio.New("minio-server-address:9000", &minio.Options{ Creds: credentials.NewStaticV4("access-key", "secret-key", ""), }) if err != nil { log.Fatalln(err) } var opts minio.GetObjectOptions // Add extract header to request: opts.Set("x-minio-extract", "true") // Download API.md from the archive rd, err := s3Client.GetObject(context.Background(), "your-bucket", "path/to/file.zip/data.csv", opts) if err != nil { log.Fatalln(err) } _, err = io.Copy(os.Stdout, rd) if err != nil { log.Fatalln(err) } }该示例下载path/to/file.zip内的data.csv,并把文件内容直接输出到 stdout;出错时通过log.Fatalln终止。
AWS JS SDK v2(your-bucket、path/to/file.zip/、path/to/file.zip/data.csv均为需要替换的占位值;header 通过on('build')钩子在签名前注入):
var AWS = require('aws-sdk'); var s3 = new AWS.S3({ accessKeyId: 'YOUR-ACCESSKEYID' , secretAccessKey: 'YOUR-SECRETACCESSKEY' , endpoint: 'http://127.0.0.1:9000' , s3ForcePathStyle: true, signatureVersion: 'v4' }); // List all contents stored in the zip archive s3.listObjectsV2({Bucket : 'your-bucket', Prefix: 'path/to/file.zip/'}). on('build', function(req) { req.httpRequest.headers['X-Minio-Extract'] = 'true'; }). send(function(err, data) { if (err) { console.log("Error", err); } else { console.log("Success", data); } }); // Download a file in the archive and store it in /tmp/data.csv var file = require('fs').createWriteStream('/tmp/data.csv'); s3.getObject({Bucket: 'your-bucket', Key: 'path/to/file.zip/data.csv'}). on('build', function(req) { req.httpRequest.headers['X-Minio-Extract'] = 'true'; }). on('httpData', function(chunk) { file.write(chunk); }). on('httpDone', function() { file.end(); }). send();如何判断操作成功
示例代码本身给出的判断方式:
- 列出:boto3 示例
print(response)打印 ListObjectsV2 的响应;JS 示例的回调在失败时打印Error和错误对象,成功时打印Success和数据。如果列出的条目里出现了你预期在 ZIP 内的文件路径,说明x-minio-extractheader 与Prefix均配置正确。 - 下载:JS 示例把内容写入
/tmp/data.csv(httpDone时结束写流);boto3 示例落盘到/tmp/data.csv;Go 示例把内容输出到 stdout。检查目标文件内容与 ZIP 内原文件一致即完成。
文档没有给出固定的示例输出,上面各打印内容以你实际环境中返回的响应为准。
限制与边界
来自 docs/extensions/s3zip/README.md 的 "Requirements and limits",直接使用 ZIP 内文件前应先确认归档满足这些条件:
ListObjectsV2只能列出对象最近一个版本的 ZIP 归档内容,仅适用于版本化 bucket。- 列出 ZIP 内容必须使用
ListObjectsV2。 - 不支持对 ZIP 内单个文件发起
GetObject/HeadObject的Range 请求。 - ZIP 内文件名保持原样不做修改,但某些名字可能构成非法路径;命名安全性需参照 S3 对象 key 命名规范自行检查。
- 如果 ZIP 的中心目录(directory)不在文件的最后 100MB 范围内,该文件将不被解析。
- 单个 ZIP 内允许的最大规模为 100M;同时文档建议单个 ZIP 内文件数控制在 100,000 以内,以获得性能与内存的合理折中。
- 除文件大小外的属性(修改时间、header、标签等)都只绑定在 ZIP 文件整体上,只能对整个 ZIP 设置;同理,bucket 复制(replication)复制的是整个 ZIP 文件而不是其中单个文件。
- 响应的
Content-Type由文件扩展名决定(按 Gomime.TypeByExtension的规则解析)。
如果归档超出上述限制(例如中心目录不在最后 100MB 内),该 ZIP 不会被解析,此时只能回退到先下载整个 ZIP 再本地处理的方案。
【免费下载链接】minioMinIO is a high-performance, S3 compatible object store, open sourced under GNU AGPLv3 license.项目地址: https://gitcode.com/GitHub_Trending/mi/minio
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考