# 分布式对象存储 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方法即可.