Flutter中使用minio_new库

前言


在移动开发中,我们常常会遇到需要在App中处理文件上传和下载的需求。Minio是一个开源的对象存储服务,它兼容Amazon S3云存储服务接口,可以用于存储大规模非结构化的数据。

开始之前


在pubspec.yaml文件中添加minio_new库的依赖:

dependencies:minio_new: ^1.0.2

运行flutter pub get命令来获取依赖。可去pub上看 minio_new 最新版本。

初始化Minio客户端


需要先创建一个Minio客户端的实例。这个实例需要配置Minio服务器的连接信息,包括服务器的URL、端口号、访问密钥和密钥等。

var minio = Minio(endPoint: 'your-minio-server.com',port: 9000,useSSL: false,accessKey: 'your-access-key',secretKey: 'your-secret-key',
);

参数介绍:
useSSL:指定是否使用 SSL 连接。如果设置为 true,则使用 HTTPS 协议进行连接;如果设置为 false,则使用 HTTP 协议。
endPoint:指定 MinIO 服务器的终端节点(Endpoint)。这是 MinIO 服务器的主机名或 IP 地址。
port:指定连接 MinIO 服务器的端口号。
accessKey:指定用于身份验证的 MinIO 服务器的访问密钥。这是访问 MinIO 存储桶和对象所需的身份验证凭据之一,就是账号。
secretKey:指定用于身份验证的 MinIO 服务器的秘密密钥。与访问密钥一同用于身份验证,就是密码。

创建桶(Bucket)


在Minio中,桶(Bucket)是一种用于组织和存储对象的容器。类似于文件系统中的文件夹,桶在Minio中用于对对象进行逻辑分组和管理。每个桶都具有唯一的名称,并且可以在Minio服务器上创建多个桶。

桶的命名规则:只能包含小写字母、数字和连字符(-),并且长度必须在3到63个字符之间。桶的名称在Minio服务器上必须是唯一的。

 Future<void> createBucket(String bucketName) {minio.makeBucket(bucketName);//设置桶的公用权限,这样外界才能通过链接访问return minio.setBucketPolicy(bucketName, {"Version": "2012-10-17","Statement": [{"Sid": "PublicRead",//一个可选参数,表示这个策略的 ID,可以随意填写。"Effect": "Allow",//表示策略的效果,如果希望所有人都可以读取,那么这里就填写 'Allow'。"Principal": "*",//表示策略的主体,如果希望所有人都可以读取,那么这里就填写 '*'。"Action": ["s3:GetObject"],//一个数组,表示允许的操作,如果希望所有人都可以读取,那么就填写 ['s3:GetObject']。"Resource": ["arn:aws:s3:::$bucketName/*"]//一个数组,表示策略的资源,如果希望所有人都可以读取桶中的所有对象,那么就填写 ['arn:aws:s3:::your_bucket/*']。}]});}

因为无论是上传还是下载文件都是基于桶进行操作的,所以初始化之后,在上传文件之前需要先创建桶,可以通过minio.bucketExists事先来判断桶是否存在。

如果不设置桶的权限的话,也就是不调用上面minio.setBucketPolicy方法,默认创建的桶是私有的,外界不能通过链接访问相关文件,出了调用minio.setBucketPolicy设置权限外,也可以在Minio后台设置桶的权限,如下图:
在这里插入图片描述

上传文件


 ///上传文件Future<String> uploadFile(String filename, String filePath) async {minio.fPutObject(bucketName, filename, filePath);//返回上传文件的完整访问路径return getUrl(filename);}

bucketName:要上传到哪个桶就写哪个桶名。

filename: 文件名,如:a.png。

filePath: 要上传文件的路径。

下载文件同理。

完整代码


minio.dart

import 'dart:async';
import 'dart:io';import 'package:ecology/utils/log_util.dart';
import 'package:ecology/utils/toast.dart';
import 'package:minio_new/io.dart';
import 'package:minio_new/minio.dart';
import 'package:minio_new/models.dart';
import 'package:path/path.dart' show dirname;
import 'package:path_provider/path_provider.dart';// ignore: unused_import
import 'package:rxdart/rxdart.dart';class Prefix {bool isPrefix;String key;String prefix; //使用前缀可以帮助你更好地组织和管理对象,避免冲突和重复,并方便批量操作,不使用传''Prefix({required this.key, required this.prefix, required this.isPrefix});
}var _minio;Future<Minio> _resetMinio() async {//固定配置-换成你实际的bool useSSl = false;String endPoint = 'red.xxx.com';int port = 9000;String accessKey = 'xxx';String secretKey = 'xxx';try {_minio = Minio(useSSL: useSSl,endPoint: endPoint,port: port,accessKey: accessKey,secretKey: secretKey,region: 'cn-north-1',);} catch (err) {XToast.show(err.toString());return Future.error(err);}return _minio;
}class MinioController {late Minio minio;String bucketName;String prefix;static resetMinio() async {await _resetMinio();}/// maximum object size (5TB)final maxObjectSize = 5 * 1024 * 1024 * 1024 * 1024;///传入唯一桶名,自动初始化桶MinioController({required this.bucketName,  this.prefix = ''}) {if (_minio is Minio) {minio = _minio;//初始化桶-由已有用户切换为新用户的情况下buckerExists(bucketName).then((exists) {if(!exists) {createBucket(bucketName);}});} else {_resetMinio().then((_) {minio = _;//初始化桶buckerExists(bucketName).then((exists) {if(!exists) {createBucket(bucketName);}});});}}///用于列出存储桶中未完成的分块上传任务。这个函数允许你获取所有处于未完成状态的分块上传任务的信息,以便你可以对其进行管理或继续上传。Future<List<IncompleteUpload>> listIncompleteUploads({String? bucketName}) async {final list =minio.listIncompleteUploads(bucketName ?? this.bucketName, '').toList();return list;}///获取桶对象///用于获取指定桶中的对象列表,并返回一个包含前缀列表和对象列表的MapFuture<Map<dynamic, dynamic>> getBucketObjects(String prefix) async {//listObjectsV2:列出指定桶中的对象。它返回一个 Stream 对象,该对象会按需逐个返回对象信息。final objects =minio.listObjectsV2(bucketName, prefix: prefix, recursive: false);final map = {};await for (var obj in objects) {final prefixs = obj.prefixes.map((e) {final index = e.lastIndexOf('/') + 1;final prefix = e.substring(0, index);final key = e;return Prefix(key: key, prefix: prefix, isPrefix: true);}).toList();map['prefixes'] = prefixs;map['objests'] = obj.objects;}return map;}///获取桶列表Future<List<Bucket>> getListBuckets() async {return minio.listBuckets();}///桶是否存在Future<bool> buckerExists(String bucket) async {return minio.bucketExists(bucket);}///下载文件Future<void> downloadFile(filename) async {final dir = await getExternalStorageDirectory();minio.fGetObject(bucketName, prefix + filename, '${dir?.path}/${prefix + filename}').then((value) {});}///上传文件Future<String> uploadFile(String filename, String filePath) async {minio.fPutObject(bucketName, filename, filePath);//返回上传文件的完整访问路径return getUrl(filename);}///批量上传文件Future<void> uploadFiles(List<String> filepaths, String bucketName) async {for (String filepath in filepaths) {String filename = filepath.split('/').last;await minio.fPutObject(bucketName, filename, filepath,);}}String getUrl(String filename) {return 'http://${minio.endPoint}:${minio.port}/$bucketName/$filename';}///用于生成一个预签名的 URL,该 URL 允许在一定时间内以有限的权限直接访问 MinIO 存储桶中的对象Future<String> presignedGetObject(String filename, {int? expires}) {return minio.presignedGetObject(bucketName, filename, expires: expires);}///获取一个文件一天的访问链接Future<String> getPreviewUrl(String filename) {return presignedGetObject(filename, expires: 60 * 60 * 24);}/// 可多删除和单删除Future<void> removeFiles(List<String> filenames) {return minio.removeObjects(bucketName, filenames);}///创建桶Future<void> createBucket(String bucketName) {minio.makeBucket(bucketName);//设置桶的公用权限,这样外界才能通过链接访问return minio.setBucketPolicy(bucketName, {"Version": "2012-10-17","Statement": [{"Sid": "PublicRead",//一个可选参数,表示这个策略的 ID,可以随意填写。"Effect": "Allow",//表示策略的效果,如果希望所有人都可以读取,那么这里就填写 'Allow'。"Principal": "*",//表示策略的主体,如果希望所有人都可以读取,那么这里就填写 '*'。"Action": ["s3:GetObject"],//一个数组,表示允许的操作,如果希望所有人都可以读取,那么就填写 ['s3:GetObject']。"Resource": ["arn:aws:s3:::$bucketName/*"]//一个数组,表示策略的资源,如果希望所有人都可以读取桶中的所有对象,那么就填写 ['arn:aws:s3:::your_bucket/*']。}]});}///移除桶Future<void> removeBucket(String bucketName) {return minio.removeBucket(bucketName);}///用于获取 MinIO 存储桶中对象的部分内容,即获取对象的部分数据。这个函数可以用于实现断点续传、分片下载或其他需要获取对象部分内容的场景。Future<dynamic> getPartialObject(String bucketName, String filename, String filePath,{required void Function(int downloadSize, int? fileSize) onListen,required void Function(int downloadSize, int? fileSize) onCompleted,required void Function(StreamSubscription<List<int>> subscription)onStart}) async {final stat = await this.minio.statObject(bucketName, filename);final dir = dirname(filePath);await Directory(dir).create(recursive: true);final partFileName = '$filePath.${stat.etag}.part.minio';final partFile = File(partFileName);IOSink partFileStream;var offset = 0;final rename = () => partFile.rename(filePath);if (await partFile.exists()) {final localStat = await partFile.stat();if (stat.size == localStat.size) return rename();offset = localStat.size;partFileStream = partFile.openWrite(mode: FileMode.append);} else {partFileStream = partFile.openWrite(mode: FileMode.write);}final dataStream =(await minio.getPartialObject(bucketName, filename, offset)).asBroadcastStream(onListen: (sub) {if (onStart != null) {onStart(sub);}});Future.delayed(Duration.zero).then((_) {final listen = dataStream.listen((data) {if (onListen != null) {onListen(partFile.statSync().size, stat.size);}});listen.onDone(() {if (onListen != null) {onListen(partFile.statSync().size, stat.size);}listen.cancel();});});await dataStream.pipe(partFileStream);if (onCompleted != null) {onCompleted(partFile.statSync().size, stat.size);}final localStat = await partFile.stat();if (localStat.size != stat.size) {throw MinioError('Size mismatch between downloaded file and the object');}return rename();}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/241908.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

快乐学Python,使用Python为电视剧主演生成词云

上篇文章我们串联了爬虫技术的几个基础环节&#xff0c;将电视剧的信息保存到了 csv 文件。这里&#xff0c;我们做个小实验&#xff1a;将主演信息生成词云。&#xff08;其他文章可看专栏文章&#xff09; 1、需求描述 将全集网抽取的电视剧&#xff08;名称、评分、主演&a…

云服务器基于Centos创建个人云盘实践经验分享

文章目录 安装运行Cloudreve安装ossfscentos更换yum源 配置ossfs挂载oss存储配置开机启动 配置cloudreve推荐阅读 安装运行Cloudreve 执行如下命令&#xff0c;下载cloudreve安装包。 wget https://labfileapp.oss-cn-hangzhou.aliyuncs.com/cloudreve_3.3.1_linux_amd64.tar…

爬虫笔记(一):实战登录古诗文网站

需求&#xff1a;登录古诗文网站&#xff0c;账号&#xff0b;密码&#xff0b;图形验证码 第一&#xff1a;自己注册一个账号&#xff0b;密码哈 第二&#xff1a;图形验证码&#xff0c;需要一个打码平台&#xff08;充钱&#xff0c;超能力power&#xff01;&#xff09;或…

纯命令行在Ubuntu中安装qemu的ubuntu虚拟机,成功备忘

信息总体还算完整&#xff0c;有个别软件更新了名字&#xff0c;所以在这备忘一下 1. 验证kvm是否支持 ________________________________________________________________ $ grep vmx /proc/cpuinfo __________________________________________________________________…

【android】 android 里写jni

目录 &#xff08;1&#xff09; 环境准备 (2) 关联c文件到gradle文件 &#xff08;3&#xff09; 生成了 (4) 书写 &#xff08;5&#xff09; 使用 &#xff08;6&#xff09;业务调用 参考文档 &#xff08;1&#xff09; 环境准备 ndk, cmake (2) 关联c文件到gr…

three.js从入门到精通系列教程002 - three.js正交相机OrthographicCamera

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>three.js从入门到精通系列教程002 - three.js正交相机OrthographicCamera</title><script src"ThreeJS/three.js"></script><script src&qu…

Android Matrix绘制PaintDrawable设置BitmapShader,手指触点为圆心scale放大原图,Kotlin(二)

Android Matrix绘制PaintDrawable设置BitmapShader&#xff0c;手指触点为圆心scale放大原图&#xff0c;Kotlin&#xff08;二&#xff09; 在 Android Matrix绘制PaintDrawable设置BitmapShader&#xff0c;手指触点为圆心scale放大原图&#xff0c;Kotlin-CSDN博客 基础上&…

Vscode 上安装 Compilot

GitHub Copilot 是由 OpenAI 和 GitHub 开发的 AI 工具。其目的是通过自动完成代码来帮助开发人员使用集成开发环境 &#xff08;IDE&#xff09;&#xff0c;如 Visual Studio Code。它目前仅作为技术预览版提供&#xff0c;因此只有已在候补名单上被接受的用户才能访问它。对…

C# wpf 实现任意控件(包括窗口)更多调整大小功能

WPF拖动改变大小系列 第一节 Grid内控件拖动调整大小 第二节 Canvas内控件拖动调整大小 第三节 窗口拖动调整大小 第四节 附加属性实现拖动调整大小 第五章 拓展更多调整大小功能&#xff08;本章&#xff09; 文章目录 WPF拖动改变大小系列前言一、添加的功能1、任意控件Drag…

分布式ID(2):雪花算法生成ID

1 雪花算法简介 这种方案大致来说是一种以划分命名空间(UUID也算,由于比较常见,所以单独分析)来生成ID的一种算法,这种方案把64-bit分别划分成多段,分开来标示机器、时间等,比如在snowflake中的64-bit分别表示如下图(图片来自网络)所示: 41-bit的时间可以表示(1L&l…

汽车微电机行业研究:预计2029年将达到188亿美元

微电机行业是技术密集型行业&#xff0c;其起源于欧洲的德国、瑞士等国家&#xff0c;发展于日本。随着改革开放&#xff0c;中国作为发展中国家&#xff0c;承接了德国、日本等发达国家的汽车微电机产业转移&#xff0c;技术扩散逐步向我国转移。 微特电机广泛应用于信息处理设…

高清网络视频监控系统技术方案

目 录 一、概述 二、建设目标及需求 &#xff08;一&#xff09;建设总目标 &#xff08;二&#xff09;需求分析 三、设计依据与设计原则 &#xff08;一&#xff09;设计依据 &#xff08;二&#xff09;设计原则 四、建设方案设计 &#xff08;一&…

Vue3新特性defineModel()便捷的双向绑定数据

官网介绍 传送门 配置 要求&#xff1a; 版本&#xff1a; vue > 3.4(必须&#xff01;&#xff01;&#xff01;)配置&#xff1a;vite.config.js 使用场景和案例 使用场景&#xff1a;父子组件的数据双向绑定&#xff0c;不用emit和props的繁重代码 具体案例 代码实…

Unity导出Android项目踩坑记录

导出的时候需要注意以下地方的配置&#xff1a; 1、buildSetting-> 设置ExportProject 2、buildsetting ->playerSetting ->设置IL2CPP 3、设置ndk edit->preferences->external tools->ndk 如果unity的ndk版本和android项目里的ndk版本不一致会报错&…

css3+javaScript实现一个左右钟摆-摇晃的红灯笼网页特效

css3javaScript实现一个左右钟摆-摇晃的红灯笼网页特效&#xff01;前天逛博客时无意中看见了&#xff0c;别人的博客顶部有一个会左右钟摆的摇晃的红灯笼&#xff0c;产生了想法&#xff0c;我也想给自己做一个&#xff0c;但是网上找了很多方案&#xff0c;都没有实现。终于在…

tidb Cloud 连接spring boot 项目

一、 免费试用tidbitcloud TiDB Cloud Documentation | PingCAP Docs 1.github账号登录 2.创建集群 3.点击对应集群cludter0 导入数据 导入 本地导入只支持csv文件&#xff0c;其他导入需要AWZ账号使用S3云存储 二、连接spingboot项目 选择java&#xff0c;复制下面的jd…

spring boot学习第八篇:通过spring boot、jedis实现秒单

参考&#xff1a;Redis实现分布式锁的7种方案 - 知乎 1、 准备数据库表&#xff0c;如下SQL表示库存表&#xff0c;有主键ID和库存数量字段 CREATE TABLE t_stock (id bigint(20) NOT NULL AUTO_INCREMENT,quantity bigint(20) NOT NULL,PRIMARY KEY (id) ) ENGINEInnoDB DEF…

Transformer详解(附代码实现及翻译任务实现)

一&#xff1a;了解背景和动机 阅读Transformer论文&#xff1a; 阅读原始的Transformer论文&#xff1a;“Attention is All You Need”&#xff0c;由Vaswani等人于2017年提出&#xff0c;是Transformer模型的开创性工作。 二&#xff1a;理解基本构建块 注意力机制&#…

源码:Spring常规Bean创建过程

Bean创建过程&#xff1a; 一、版本 5.3.10二、学习内容 Bean创建过程源码三、Bean生命周期 时间轴地址&#xff1a;点击 四、bean创建过程脑图总结 脑图地址&#xff1a;点击 五、源码过程 说明&#xff1a; bean创建入口一般都是通过getBean(xxx);方法进入的&#xf…

C 语言->编译和链接实现原理

✅作者简介&#xff1a;大家好&#xff0c;我是橘橙黄又青&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;橘橙黄又青-CSDN博客 今天学习&#xff1a;浅学编译和链接内部实现原理 前提&#xff1a;本文是在gcc编译环…