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.mzph.cn/news/632867.shtml

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

相关文章

CSV文件中json列的处理2

如上所示&#xff0c;csv文件中包含以中括号{}包含的json字段&#xff0c;可用如下方法提取&#xff1a; import pandas as pd from datetime import date todaystr(date.today()) import jsonfilepath/Users/kangyongqing/Documents/kangyq/202401/调课功能使用统计/ file104…

kotlin Kmp多平台模板生成

地址: Kotlin Multiplatform Wizard | JetBrains 可生成kotlin多个平台模板 https://terrakok.github.io/Compose-Multiplatform-Wizard/

分享 GitHub 上的敏感词汇工具类:sensitive-word

&#x1f604; 19年之后由于某些原因断更了三年&#xff0c;23年重新扬帆起航&#xff0c;推出更多优质博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Mi…

x-www-form-urlencoded接收方式代码示例

数据回推方式是 “x-www-form-urlencoded”&#xff0c;可以选择使用 GET 或 POST 方法来接收数据回推。 使用 GET 方法接收数据回推时&#xff0c;您可以将数据作为查询参数附加在请求的 URL 中。例如&#xff1a; http://example.com/callback?param1value1&param2val…

Vue学习笔记9--vuex(专门在Vue中实现集中式状态(数据)管理的一个Vue插件)

一、vuex是什么&#xff1f; 概念&#xff1a;专门在Vue中实现集中式状态&#xff08;数据&#xff09;管理的一个Vue插件&#xff0c;对vue应用中多个组件的共享状态进行集中式的管理&#xff08;读/写&#xff09;&#xff0c;也是一种组件间通信的方式&#xff0c;且适用于…

统计学-R语言-6.1

文章目录 前言参数估计的原理总体、样本和统计量点估计区间估计评价估计量的标准有效性 总体均值的区间估计一个总体均值的估计&#xff08;大样本&#xff09;一个总体均值的估计&#xff08;小样本估计&#xff09; 练习 前言 本篇文章将开始介绍参数估计的相关知识。 参数估…

关于java的继承

关于java的继承 我们在上一篇文章中&#xff0c;了解到了封装&#xff0c;我们本篇文章来介绍一下面向对象的第二大特点&#xff0c;继承&#xff0c;还是遵循结合现实生活中的实际情况&#xff0c;理解着去学习&#xff0c;能更好的加深印象&#x1f600;。 一、继承 继承的…

C++、QT 数字合成游戏

一、项目介绍 数字合成游戏 基本要求&#xff1a; 1&#xff09;要求游戏界面简洁美观&#xff0c;且符合扫雷的游戏风格。 2&#xff09;需要有游戏操作或者规则说明&#xff0c;方便玩家上手。 3&#xff09;需具有开始游戏&#xff0c;暂停游戏&#xff0c;结束游戏等方便玩…

Java17新特性详解含示例代码(值得珍藏)

1. 概述 Java 17 是 Java 开发工具包&#xff08;JDK&#xff09;的一个重要版本&#xff0c;它带来了一系列的新特性和改进&#xff0c;以进一步增强 Java 语言的功能和性能。以下是 Java 17 中的一些主要新特性及其详细说明。 2. 新特性详解 JEP 356: Enhanced Pseudo-Ran…

【​电力电子在电力系统中的应用​】6 滞环电流控制的PWM整流器 + STATCOM整流器 + APF仿真

【仅供参考】 【2023.06西南交大电力电子在电力系统中的应用】 目录 步骤一&#xff1a;基于滞环电流控制的PWM整流器仿真 1.1 仿真要求 1.2 仿真电路原理及设计 1.2.1 主电路的搭建 1.2.2 控制电路的搭建 1.3 波形分析 步骤二&#xff1a;从PWM整流器到STATCOM仿真 2…

全等三角形定率

一.有两角夹一边分别相等的两个三角形全等 数学证明: 设△ A B C 与△ A 1 B 1 C 1 ∠ B ∠ B 1 , ∠ C ∠ C 1 , B 1 C 1 B C 设△ABC与△A_1B_1C_1∠B∠B_1,∠C∠C_1,B_1C_1BC 设△ABC与△A1​B1​C1​∠B∠B1​,∠C∠C1​,B1​C1​BC ①移动 ∠ B 1 与 ∠ B 重合 , 边 B…

Android WorkManager入门(二)

WorkManager入门 上一篇前言创建 WorkRequest并提交 定时的任务&#xff08;PeriodicWorkRequest&#xff09;配合约束使用定义执行范围失败后的重试为WorkRequest打上TAG其他取消方法 传参和返回参数总结参考资料 上一篇 Android WorkManager入门&#xff08;一&#xff09; …

EMQX安装和Java使用

一、EMQX介绍 EMQX是大规模分布式MQTT消息服务器&#xff0c;可以高效可靠连接海量物联网设备&#xff0c;实时处理分发消息与事件流数据&#xff0c;助力构建关键业务的物联网与云应用。EMQX 作为物联网应用开发和物联网平台搭建必须用到的基础设施软件&#xff0c;主要在边缘…

VSCode使用Makefile Tools插件开发C/C++程序

提起Makefile&#xff0c;可能有人会觉得它已经过时了&#xff0c;毕竟现在有比它更好的工具&#xff0c;比如CMake&#xff0c;XMake&#xff0c;Meson等等&#xff0c;但是在Linux下很多C/C源码都是直接或者间接使用Makefile文件来编译项目的&#xff0c;可以说Makefile是基石…

qt学习:进度条,水平滑动条,垂直滑动条+rgb调试实战

目录 水平滑动条&#xff0c;垂直滑动条 常用信号 进度条 常用信号 修改进度条 例子 rgb调色 配置ui界面 编写3个进度条的事件函数 添加链表容器和按钮索引 在.h里的类定义 初始化链表容器和按钮索引 编写添加颜色的按钮点击事件函数 效果 水平滑动条&#xff0c…

Java-初识正则表达式 以及 练习

目录 什么是正则表达式&#xff1f; 1. 正则表达式---字符类&#xff08;一个大括号匹配一个字符&#xff09;&#xff1a; 2. 正则表达式---预字符类&#xff08;也是匹配一个字符&#xff09;&#xff1a; 正则表达式---数量词 &#xff08;可以匹配多个字符&#xff09;…

【前后端的那些事】15min快速实现图片上传,预览功能(ElementPlus+Springboot)

文章目录 Element Plus SpringBoot实现图片上传&#xff0c;预览&#xff0c;删除效果展示 1. 后端代码1.1 controller1.2 service 2. 前端代码2.1 路由创建2.2 api接口2.2 文件创建 3. 前端上传组件封装 前言&#xff1a;最近写项目&#xff0c;发现了一些很有意思的功能&…

网络安全产品之认识WEB应用防火墙

随着B/S架构的广泛应用&#xff0c;Web应用的功能越来越丰富&#xff0c;蕴含着越来越有价值的信息&#xff0c;应用程序漏洞被恶意利用的可能性越来越大&#xff0c;因此成为了黑客主要的攻击目标。传统防火墙无法解析HTTP应用层的细节&#xff0c;对规则的过滤过于死板&#…

移动云助力智慧交通数智化升级

智慧交通是在整个交通运输领域充分利用物联网、空间感知、云计算、移动互联网等新一代信息技术&#xff0c;综合运用交通科学、系统方法、人工智能、知识挖掘等理论与工具&#xff0c;以全面感知、深度融合、主动服务、科学决策为目标&#xff0c;推动交通运输更安全、更高效、…

软件设计师5--CISC与RISC

软件设计师5--CISC与RISC 考点1&#xff1a;CISC与RISC有什么不同考点2&#xff1a;CISC与RISC比较&#xff0c;分哪些维度例题&#xff1a; 考点1&#xff1a;CISC与RISC有什么不同 考点2&#xff1a;CISC与RISC比较&#xff0c;分哪些维度 例题&#xff1a; 1、以下关于RISC…