51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

分布式对象存储MinIO Sdk的使用

# 分布式对象存储 MinIO Sdk 的使用 {#分布式对象存储-minio-sdk-的使用}

本文介绍开源的分布式对象存储 MinIO Sdk 的使用。对象存储系统相比于传统的 NAS 文件系统有很多的优势,访问效率高、方便扩容,支持分布式等特性。MinIO 基于 Goland 开发,所以部署非常方便。

MinIO 服务的搭建步骤请前往搭建分布式对象存储服务 MinIO-单点模式

注意:
官方的中文文档内容更新不及时,导致演示代码错误,请切换为英文官网。

# 1. Golang sdk {#_1-golang-sdk}

# 1.1 demo 代码 {#_1-1-demo-代码}

package test

import (
	"context"
	"github.com/minio/minio-go/v7/pkg/credentials"
	"log"
	"testing"
	"github.com/minio/minio-go/v7"
)

/**
@author 王世彪
	个人博客: https://sofineday.com?from=apiproject
	微信: 645102170
	QQ: 645102170
*/

/**
测试MinIO对象存储服务的sdk
 */
func TestMinIO(t *testing.T) {
	ctx := context.Background()
	endpoint := "172.18.100.177:9000"
	accessKeyID := "minioadmin"
	secretAccessKey := "minioadmin"
	useSSL := false

	// Initialize minio client object.
	minioClient, err := minio.New(endpoint, &minio.Options{
		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
		Secure: useSSL,
	})
	if err != nil {
		log.Fatalln(err)
	}

	// Make a new bucket called mymusic.
	bucketName := "mymusic"
	location := "us-east-1"

	err = minioClient.MakeBucket(ctx, bucketName, minio.MakeBucketOptions{Region: location})
	if err != nil {
		// Check to see if we already own this bucket (which happens if you run this twice)
		exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
		if errBucketExists == nil && exists {
			log.Printf("We already own %s\n", bucketName)
		} else {
			log.Fatalln(err)
		}
	} else {
		log.Printf("Successfully created %s\n", bucketName)
	}

	// Upload the zip file
	objectName := "百事可乐的视频1"
	filePath := "/home/wangshibiao/test/百事可乐创意广告恶搞伦敦路人.mp4"
	contentType := "video/mpeg4"

	// Upload the zip file with FPutObject
	n, err := minioClient.FPutObject(ctx, bucketName, objectName, filePath, minio.PutObjectOptions{ContentType: contentType})
	if err != nil {
		log.Fatalln(err)
	}
	log.Println(n)

	log.Printf("Successfully uploaded %s\n", objectName)
}

注意,如上代码中minioClient.FPutObject(ctx, bucketName, objectName, filePath, minio.PutObjectOptions{ContentType: contentType})的contentType参数也可以不指定.服务端会自动检测.

若想创建子目录,则在objectName的定义中指定出目录结构即可,服务端会自动创建目录.注意,不能以/开头.

objectName := "mp4视频/百事可乐的视频1.mp4"

# 1.2 效果 {#_1-2-效果}

  • 通过后台管理查看

  • 通过客户端 mc 查看

    / # mc ls minio/mymusic [2020-10-30 02:23:28 UTC] 14MiB 百事可乐的视频1 / #

# 1.3 封装为工具函数 {#_1-3-封装为工具函数}

可以将sdk封装为通用的函数, 方便其它部分调用.r 如下:

package minio

import (
	"context"
	"novel/config"
	"novel/log"
	"novel/util"
	"os"
	"strings"

	"github.com/minio/minio-go/v7"
	"github.com/minio/minio-go/v7/pkg/credentials"
	"go.uber.org/zap"
)

var minioClient *minio.Client

/**
初始化minioClient
*/
func Init() {
	if !config.GlobalConfig.MinioSwitch {
		log.Info(nil, "初始化minioClient, 开关未开启")
		return
	}

	var err error
	// Initialize minio client object.
	minioClient, err = minio.New(config.GlobalConfig.MinioEndpoint, &minio.Options{
		Creds:  credentials.NewStaticV4(config.GlobalConfig.MinioAccessKeyID, config.GlobalConfig.MinioSecretAccessKey, ""),
		Secure: config.GlobalConfig.MinioUseSSL,
	})
	if err != nil {
		log.Error(nil, "初始化minioClient, 创建client object, 失败", zap.Error(err))
		panic("初始化minioClient,失败")
	}

	bucketName := config.GlobalConfig.MinioBucketName
	ctx := context.Background()
	err = minioClient.MakeBucket(ctx, bucketName, minio.MakeBucketOptions{Region: config.GlobalConfig.MinioLocation})
	if err != nil {
		// Check to see if we already own this bucket (which happens if you run this twice)
		exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
		if errBucketExists == nil && exists {
			log.Warn(nil, "初始化minioClient, bucket已存在", zap.Any("bucketName", bucketName))
		} else {
			log.Error(nil, "初始化minioClient, 失败", zap.Any("bucketName", bucketName), zap.Error(errBucketExists))
		}
	} else {
		log.Info(nil, "初始化minioClient, 完成", zap.Any("bucketName", bucketName))
	}
}

/**
上传文件到minio存储
localFilePath: 本地的文件路径
serverFilePath: 对应到服务端的文件路径,是否以/开头均可
*/
func UploadToMinio(localFilePath string, serverFilePath string) (url string, err error) {
	objectName := strings.TrimPrefix(serverFilePath, "/")
	url = "http://"+config.GlobalConfig.MinioEndpoint + "/" + objectName

	ctx := context.Background()
	uploadInfo, err := minioClient.FPutObject(ctx, config.GlobalConfig.MinioBucketName, objectName, localFilePath, minio.PutObjectOptions{})
	if err != nil {
		log.Error(nil, "上传文件到minio存储, 失败", zap.Any("localFilePath", localFilePath), zap.Any("objectName", objectName), zap.Error(err))
		return url, nil
	}

	log.Info(nil, "上传文件到minio存储, 完成", zap.Any("objectName", objectName), zap.Any("uploadInfo", uploadInfo))
	return url, nil
}

/**
下载文件到Minio存储的指定bucket中:
bucket在配置文件中指定
若不指定serverFilePath参数, 则生成一个默认路径
*/
func DownloadImgToMinio(url string, serverFilePath ...string) (path string, minioUrl string, err error) {
	relativeFilePath := util.GetCurrentDateString("/") + "/" + util.GenUniqueId().String() + ".jpg"
	//若指定了serverFilePath,
	if len(serverFilePath) > 0 {
		relativeFilePath = serverFilePath[0]
	}
	localFilePath := "/tmp/" + relativeFilePath

	if err := util.DownloadFileByLocalPath(url, localFilePath); err != nil {
		log.Error(nil, "下载文件到Minio存储, 下载文件, 失败", zap.Any("url", url), zap.Error(err))
		return relativeFilePath, "", err
	}

	minioUrl, err = UploadToMinio(localFilePath, relativeFilePath);
	if  err != nil {
		log.Error(nil, "下载文件到Minio存储, 上传到minio, 失败", zap.Any("url", url), zap.Any("serverFilePath", serverFilePath), zap.Error(err))
		return relativeFilePath, "", err
	}

	//删除本地文件
	if err := os.Remove(localFilePath); err != nil {
		log.Error(nil, "下载文件到Minio存储, 删除本地文件, 失败", zap.Any("localFilePath", localFilePath))
	}

	log.Info(nil, "下载文件到Minio存储, 完成", zap.Any("url", url), zap.Any("serverFilePath", serverFilePath), zap.Any("relativeFilePath", relativeFilePath), zap.Any("minioUrl", minioUrl))
	return config.GlobalConfig.MinioBucketName+"/"+relativeFilePath, minioUrl, nil
}

在系统启动时, 调用Init方法执行初始化, 然后在需要做文件上传时, 调用DownloadImgToMinio方法即可.

赞(1)
未经允许不得转载:工具盒子 » 分布式对象存储MinIO Sdk的使用