.net 8 集成 MinIO文件存储服务,实现bucket管理,以及文件对象的基本操作

一、准备工作

1、本地部署MinIO服务

2、创建MinIO的Access Key

3、创建.net 项目

4、下载MinIO sdk

5、相关文档

二、编写MinIO工具类

三、管理存储桶

1、MyBucket类

(1)判断bucket是否存在

(2)新建bucket

(3)删除bucket 

(4)获取bucket列表

2、BucketController

3、实现效果

(1)判断bucket是否存在

(2)新建bucket

(3)删除bucket

(4)获取bucket列表

四、管理文件

1、MyObject类

(1)下载文件对象

(2)上传文件对象

(3)删除文件对象

(4)获取文件对象URL

2、ObjectController 

3、实现效果

(1)下载指定文件

(2)上传指定文件

(3)删除指定文件 

(4)获取指定文件URL 


一、准备工作

1、本地部署MinIO服务

需要在本地部署MinIO,并启动服务;可以参考这篇文章

Windows部署MinIO,搭建本地对象存储服务-CSDN博客

2、创建MinIO的Access Key

在MinIO控制台,选择【Access Keys】,点击【Create access key】;

点击【Create】创建用于连接MinIO服务的Key和Secret(很重要,一定要另存下来);

3、创建.net 项目

打开Visual Studio,新建项目,选择Web Api框架

选择.net8.0

4、下载MinIO sdk

使用NuGet包管理器找到并安装MinIIO的sdk,如下图所示,

这里安装的是最新版6.0.2;

5、相关文档

.NET API 开发文档(英文)

.NET API 参考文档(中文)

以官网的英文文档为主,中文文档为辅;

二、编写MinIO工具类

在代码中编写一个用来连接MinIO服务的工具类【MinIO.cs】,放在项目的【Helper】文件夹中;

【Helper/MinIO.cs】

using Minio;

namespace Zyl_MinIO_Demo.Helper
{
    public class MinIO
    {
        private static string endPoint = "127.0.0.1:9001";  
        private static string accessKey = "连接minio服务的key";   
        private static string secretKey= "连接minio服务的secret";
        private static bool secure = false; 

        public static MinioClient CreateMinioClient()
        {
            MinioClient minioClient = (MinioClient)new MinioClient()
                  .WithEndpoint(endpoint)
                  .WithCredentials(accessKey, secretKey)
                  .WithSSL(secure)   
                  .Build();
            return minioClient;
        }
    }
}
// 该方法用来初始化MinIO对象。
MinioClient minioClient = new MinioClient()

        .WithEndpoint(endPoint)

        .WithCredentials(accessKey, secretKey)

        .WithSSL(secure)

        .Build(); 
  • endPoint :MinIO服务启动的URL,注意自己启动服务的端口号;

  • accessKey :在MinIO控制台申请的Access Key;
  • secretKey:在MinIO控制台申请的Access Secret;

  • secure :布尔值(默认值  true),是否启用HTTPS;

三、管理存储桶

1、MyBucket类

在【Managers】文件夹中新建【MyBucket】类,用来管理存储桶;

【Managers/MyBucket.cs】

using Minio.DataModel.Args;
using Minio.Exceptions;
using Minio;
using Zyl_MinIO_Demo.Helper;
using Minio.DataModel.Result;

namespace Zyl_MinIO_Demo.Managers
{
    public class MyBucket
    {
        // 实例化 minioClient
        private static MinioClient minioClient = MinIO.CreateMinioClient();

        /// <summary>
        /// 1、判断bucket是否存在
        /// </summary>
        /// <param name="bucketName"></param>
        /// <returns></returns>
        public static async Task<string> IsExistStr(string bucketName){

            try
            {
                BucketExistsArgs args = new BucketExistsArgs().WithBucket(bucketName);

                bool found = await minioClient.BucketExistsAsync(args).ConfigureAwait(false);

                Console.WriteLine("found。。。。。。", found);

                if (found)
                {
                    Console.WriteLine($"{bucketName}桶已存在");
                    return $"{bucketName}桶已存在";
                }
                else
                {
                    Console.WriteLine($"{bucketName}桶不存在");
                    return $"{bucketName}桶不存在";
                }
            }
            catch (MinioException e)
            {
                Console.WriteLine("[Bucket]  Exception: {0}", e);
                return "出错啦!!!";
            }
        }

        /// <summary>
        /// 2、创建一个bucket
        /// </summary>
        /// <param name="bucketName"></param>
        /// <returns></returns>
        public static async Task<string> Create(string? bucketName)
        {
            try
            {
                BucketExistsArgs args = new BucketExistsArgs().WithBucket(bucketName);

                bool found = await minioClient.BucketExistsAsync(args).ConfigureAwait(false);

                if (found)
                {
                    return $"{bucketName}桶已存在";
                }
                else
                {
                    MakeBucketArgs makeBucketArgs = new MakeBucketArgs().WithBucket(bucketName);
                    await minioClient.MakeBucketAsync(makeBucketArgs).ConfigureAwait(false);

                    return $"{bucketName}桶已成功创建";
                }
            }
            catch (MinioException e)
            {
                Console.WriteLine("[Bucket]  Exception: {0}", e);
                return "出错啦!!!";
            }
        }

        /// <summary>
        /// 3、移除一个bucket
        /// </summary>
        /// <param name="bucketName"></param>
        /// <returns></returns>
        public static async Task<string> Delete(string? bucketName)
        {
            try
            {
                BucketExistsArgs args = new BucketExistsArgs().WithBucket(bucketName);

                bool found = await minioClient.BucketExistsAsync(args).ConfigureAwait(false);

                if (!found)
                {
                    return $"{bucketName}桶不存在";
                }
                else
                {
                    RemoveBucketArgs removeBucketArgs = new RemoveBucketArgs().WithBucket(bucketName);

                    await minioClient.RemoveBucketAsync(removeBucketArgs);

                    return $"{bucketName}桶删除成功";
                }
            }
            catch (MinioException e)
            {
                Console.WriteLine("[Bucket]  Exception: {0}", e);
                return "出错啦!!!";
            }
        }

        /// <summary>
        /// 4、获取已有的bucket列表
        /// </summary>
        /// <returns></returns>
        public static async Task<ListAllMyBucketsResult?> GetList()
        {
            try
            {
                return await minioClient.ListBucketsAsync();
            }
            catch (MinioException e)
            {
                Console.WriteLine("Error occurred: " + e);
                return null ;
            }
        }
    }
}

(1)判断bucket是否存在

Task<bool> BucketExistsAsync(BucketExistsArgs args)
  • 判断一个指定名称的存储桶是否存在
  • 返回一个布尔值true(存在),或false(不存在); 

(2)新建bucket

Task MakeBucketAsync(MakeBucketArgs args)
  • 创建一个指定名称的存储桶;
  • 创建失败,则返回异常信息;

(3)删除bucket 

Task RemoveBucketAsync(RemoveBucketArgs args)
  • 移除一个指定名称的存储桶;
  • 任务返回移除失败时的异常信息;
  • 当桶中有内容时,则不会被删除;

(4)获取bucket列表

Task<ListAllMyBucketsResult> ListBucketsAsync()
  • 用来获取buckets列表数据; 

2、BucketController

在Controllers文件夹下,新建一个空的API控制器,用来给前端人员暴露接口;

【Controllers/BucketController.cs】

using Microsoft.AspNetCore.Mvc;
using Minio;
using Minio.DataModel.Result;
using Zyl_MinIO_Demo.Managers;

namespace Zyl_MinIO_Demo.Controllers
{
    /// <summary>
    /// 管理 MinIO 中的 Bucket
    /// </summary>
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class BucketController : ControllerBase
    {
        /// <summary>
        /// 1、判断指定bucket是否存在
        /// </summary>
        /// <param name="bucketName">bucket 名称</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<string> IsBucketExit(string bucketName)
        {
            return await MyBucket.IsExist(bucketName) ?  $"{bucketName}桶已存在" : $"{bucketName}桶不存在";
        }

        /// <summary>
        /// 2、 创建bucket
        /// </summary>
        /// <param name="bucketName">bucket 名称</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<string> CreateBucket(string bucketName)
        {
            return await MyBucket.Create(bucketName);
        }

        /// <summary>
        /// 3、移除bucket
        /// </summary>
        /// <param name="bucketName">bucket 名称</param>
        /// <returns></returns>
        [HttpDelete]
        public async Task<string> DeleteBucket(string bucketName)
        {
            return await MyBucket.Delete(bucketName);
        }

        /// <summary>
        /// 4、获取bucket列表
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<ListAllMyBucketsResult?> GetBucketList()
        {
            return await MyBucket.GetList();
        }
    }
}

3、实现效果

启动项目,使用Swagger进行接口测试;

注意:

  • 需要确保,项目中已经配置了Swagger;
  • 需要确保,MinIO服务已经启动;

项目启动后的swagger页面:

.net 项目中配置 Swagger-CSDN博客 

可参考上方链接配置swagger;

先在MinIO控制台中创建一个名为zyl的bucket;

(1)判断bucket是否存在

输入桶名,点击测试;

 执行后可以看到数据正常返回;

(2)新建bucket

(3)删除bucket

(4)获取bucket列表

四、管理文件

1、MyObject类

在【Managers】文件夹中新建【MyObject】类,用来管理存储桶中的文件对象;

【Managers/MyObject.cs】

using Minio.DataModel.Args;
using Minio;
using Zyl_MinIO_Demo.Helper;
using Minio.Exceptions;

namespace Zyl_MinIO_Demo.Managers
{
    public class MyObject
    {
        private static readonly MinioClient minioClient = MinIO.CreateMinioClient();
        
        /// <summary>
        /// 1、下载文件 到本地
        /// </summary>
        public async static Task<String> DownloadFile(string bucketName, string objectName) {
            try
            {
                string folderPath = "D:\\minio-download-files\\";
                if (!Directory.Exists(folderPath)) {
                    DirectoryInfo directoryInfo = new DirectoryInfo(folderPath);
                    directoryInfo.Create();
                }
                
                StatObjectArgs statObjectArgs = new StatObjectArgs()
                                                    .WithBucket(bucketName)
                                                    .WithObject(objectName);
                await minioClient.StatObjectAsync(statObjectArgs);
                
                GetObjectArgs getObjectArgs = new GetObjectArgs()
                                                  .WithBucket(bucketName)
                                                  .WithObject(objectName)
                                                  .WithFile(folderPath + objectName);
                await minioClient.GetObjectAsync(getObjectArgs);
                return "Success";
            }
            catch (MinioException e)
            {
                return $"Failure\r\n{e.Message}";
            }
        }

        /// <summary>
        /// 2、上传文件 指定文件
        /// </summary>
        public async static Task<string> UploadFile(string bucketName,string fileFullPath)
        {
            try
            {
                // 判断bucket是否存在
                bool isExit = await MyBucket.IsExist(bucketName);

                if (!isExit)
                {
                    Console.Out.WriteLine($"{bucketName}桶不存在");

                    return $"{bucketName}桶不存在,文件上传失败";
                }

                string objectName = fileFullPath.Split("\\")[^1];

                // 上传文件
                PutObjectArgs putObjectArgs = new PutObjectArgs()
                    .WithBucket(bucketName)
                    .WithObject(objectName)
                    .WithFileName(fileFullPath)
                    .WithContentType("application/octet-stream");
                await minioClient.PutObjectAsync(putObjectArgs).ConfigureAwait(false);

                return $"{objectName}上传成功";
            }
            catch (Exception e)
            {
                return $"Failure\r\n{e.Message}";
            }
        }

        /// <summary>
        /// 3、删除 指定文件
        /// </summary>
        public async static Task<string> DeleteFile(string bucketName, string objectName)
        {
            try
            {
                // 判断bucket是否存在
                bool isExit = await MyBucket.IsExist(bucketName);

                if (!isExit)
                {
                    return $"{bucketName}桶不存在,文件删除失败";
                }

                RemoveObjectArgs removeObjectArgs = new RemoveObjectArgs()
                                .WithBucket(bucketName)
                                .WithObject(objectName);
                await minioClient.RemoveObjectAsync(removeObjectArgs);

                return $"{bucketName}桶中的{objectName}文件删除成功";
            }
            catch (MinioException e)
            {
                return $"Failure\r\n{e.Message}";
            }
        }

        /// <summary>
        /// 4、获取指定文件的url链接
        /// </summary>
        public async static Task<String> GetFileUrl(string bucketName, string objectName)
        {
            try
            {
                PresignedGetObjectArgs args = new PresignedGetObjectArgs()
                        .WithBucket(bucketName)
                        .WithObject(objectName)
                        .WithExpiry(60 * 60 * 24 * 7);
                return await minioClient.PresignedGetObjectAsync(args);
            }
            catch (MinioException e)
            {
                return $"Failure\r\n{e.Message}";
            }
        }
    
    }
}

(1)下载文件对象

Task GetObjectAsync(GetObjectArgs args)
  •  用来下载一个文件对象,并保存到本地;

(2)上传文件对象

Task PutObjectAsync(PutObjectArgs args)
  •  若上传的文件名于之前相同,则会覆盖;

(3)删除文件对象

Task RemoveObjectAsync(RemoveObjectArgs args)

(4)获取文件对象URL

Task<string> PresignedGetObjectAsync(PresignedGetObjectArgs args)
  • 返回的URL可用来直接下载该文件对象;
  • 返回的URL有效期为7天(默认),也可以自行设置(秒数);

2、ObjectController 

【Controllers/ObjectController.cs】

using Microsoft.AspNetCore.Mvc;
using Zyl_MinIO_Demo.Managers;

namespace Zyl_MinIO_Demo.Controllers
{
    /// <summary>
    /// 管理 MinIO对象(默认zyl bucket桶)
    /// </summary>
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class ObjectController : ControllerBase
    {
        /// <summary>
        /// 1、下载 bucket中的文件
        /// </summary>
        /// <remarks>
        /// 会保存在 D:\\minio-download-files 文件夹内;
        /// 若本地D盘中没有该文件夹,则会自动创建;
        /// </remarks>
        /// <param name="objectName">文件名</param>
        /// <param name="bucketName">桶名,默认zyl</param>
        [HttpPost]
        public async Task<string> DownloadObject( string objectName, string bucketName = "zyl")
        {
            return await MyObject.DownloadFile(bucketName, objectName);
        }

        ///<summary>
        /// 2、上传 本地指定文件
        /// </summary>
        /// <remarks>
        /// 上传同名文件,会覆盖之前的
        /// </remarks>
        /// <param name="fileFullPath">上传文件的完整绝对路径,例如:D:\test\test.txt</param>
        /// <param name="bucketName">桶名,默认zyl</param>
        [HttpPost]
        public async Task<string> UploadObject(string fileFullPath, string bucketName = "zyl")
        {
            return await MyObject.UploadFile(bucketName, fileFullPath);
        }

        /// <summary>
        /// 3、删除 指定桶中的指定文件
        /// </summary>
        /// <param name="objectName">文件名</param>
        /// <param name="bucketName">桶名,默认zyl</param>
        [HttpDelete]
        public async Task<string> DeleteObject(string objectName, string bucketName = "zyl")
        {
            return await MyObject.DeleteFile(bucketName, objectName);
        }

        /// <summary>
        /// 4、获取 指定文件的Url链接 (有效期 7天)
        /// </summary>
        /// <remarks>
        /// 只能是已经存在于minio中的任意文件
        /// </remarks>
        /// <param name="objectName">文件名</param>
        /// <param name="bucketName">桶名,默认zyl</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<string> GetObjectUrl(string objectName, string bucketName = "zyl") {
            return await MyObject.GetFileUrl(bucketName, objectName);
        }

    }
}

3、实现效果

在Swagger页面,可以看到我们新增的文件对象相关接口;

(1)下载指定文件

  • 这里的默认bucket,确保在使用之前已经创建;
  • 文件会下载到本地D盘的【minio-downlo-files】文件夹中,没有该文件夹会自动创建;

(2)上传指定文件

  • 第一个参数应该填写待上传文件的完整绝对路径,这里上传的是D盘下test文件夹中的text.txt文件;
  • 上传到minio服务中的文件名取自待上传的文件名,若与之前的文件名相同,会进行覆盖;

(3)删除指定文件 

(4)获取指定文件URL 

  • 需要确保minio中已经上传了该文件;
  • 将返回的URL链接放在浏览器的地址栏,按回车即可下载查看;

 ​

======================================================================

每天进步一点点,记录一下MinIO的学习笔记;

刚开始接触后端,代码略显生涩,嘻嘻嘻;

还望走过路过的各位大佬多多指点~ 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CST电磁仿真软件在兼容方向的应用

电磁兼容仿真 这篇文章主要讲述了CST在电磁兼容领域的应用。实践表明&#xff0c;发现产品的电磁兼容问题越早&#xff0c;解决问题所需的时间和成本就会越少&#xff0c;也就越容易解决电磁兼容问题。 CST电磁仿真软件针对系统设计中的诸多问题&#xff0c;例如PCB板级EMC、线…

生产环境 CentOS 7 k8s v1.28.0离线部署

背景描述&#xff1a;CentOS 7 Kubernetes 离线部署 随着云计算和微服务架构的普及&#xff0c;Kubernetes&#xff08;K8s&#xff09;已经成为容器编排的标准工具。它能够自动化应用的部署、扩展和管理&#xff0c;使得开发和运维的工作更加高效和可靠。然而&#xff0c;在一…

【MySQL备份】Percona XtraBackup全量备份实战篇

目录 1. 前言 2.准备工作 2.1.环境信息 2.2.创建备份目录 2.3.配置/etc/my.cnf文件 2.4.授予root用户BACKUP_ADMIN权限 3.全量备份 4.准备备份 5.数据恢复 6.总结 "实战演练&#xff1a;利用Percona XtraBackup执行MySQL全量备份操作详解" 1. 前言 本文…

【文末赠书13】推荐系统中冷启动环节的设计实现

【文末赠书13】《智能网联汽车&#xff1a;激光与视觉SLAM详解》 写在最前面写在最前面推荐系统中的冷启动1、用户冷启动2、物料冷启动3、PID算法 《推荐系统全链路设计&#xff1a;原理解读与业务实践》内容简介&#xff1a; &#x1f308;你好呀&#xff01;我是 是Yu欸 &am…

分享3个AI工具-包括自学AI文档和AI搜索和智能体

文章目录 通往AGI之路-自学神器秘塔AI扣子 通往AGI之路-自学神器 这是是一个有关AI知识的开源文档。 但是&#xff0c;我认为这是小白学习AI的最强王者&#xff0c;每一个想学习AI、想使用AI的人都可以把它设为首页&#xff0c;从它开始。 飞书文档&#xff1a;通往AGI之路 …

如何实现公网环境远程连接本地局域网宝塔FTP服务远程管理文件

文章目录 前言1. Linux安装Cpolar2. 创建FTP公网地址3. 宝塔FTP服务设置4. FTP服务远程连接小结 5. 固定FTP公网地址6. 固定FTP地址连接 &#x1f4a1;推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。…

基于IIS的Windows系统Django项目本地部署

参考&#xff1a; 1. 基于Windows平台的Django本地部署和腾讯云服务器上部署&#xff08;1&#xff09;_如何在服务器上发布部署django程序 csdn-CSDN博客 2.Windows server iis部署Django详细操作 - Django中文 - 博客园 (cnblogs.com) 3.在IIS中部署pythonDjango项目时出…

基于大语言模型的本地知识库问答(离线部署)

一、前言 知识库问答是一种应用广泛的系统&#xff0c;可以在许多领域发挥重要作用。不过以往的系统通常是基于固定规则、相似度检索或者seq2seq模型&#xff0c;这类系统开发成本较高、修改也较为麻烦&#xff0c;尤其在数据准备过程需要耗费大量精力。 而大语言模型&#x…

事务的影子拷贝-系统架构师(二十)

1、&#xff08;重点&#xff09;企业信息集成按照组织范围分为企业内部的信息集成和外部信息集成。在企业内部信息集成中&#xff0c;&#xff08;&#xff09;实现了不同系统之间的互操作&#xff0c;使的不同系统之间能够实现数据和方法的共享。&#xff08;&#xff09;实现…

基于Java的外卖点餐系统设计与实现

作者介绍&#xff1a;计算机专业研究生&#xff0c;现企业打工人&#xff0c;从事Java全栈开发 主要内容&#xff1a;技术学习笔记、Java实战项目、项目问题解决记录、AI、简历模板、简历指导、技术交流、论文交流&#xff08;SCI论文两篇&#xff09; 上点关注下点赞 生活越过…

Linux\ubuntu系统下载中文输入法

目录 1 系统图形化安装 1.1 打开设置 1.2 选择语言 1.3 选择简体中文 1.4 再次打开设置 1.5 选择中文 1.6 退出即可安装成功 本文主要记述在ubuntu1806下安装中文输入法的过程&#xff0c;其实Ubuntu上可以安装的中文输入法有很多种&#xff0c;可以直接通过系统安装&am…

周界入侵自动监测摄像机

当今&#xff0c;随着科技的快速发展&#xff0c;周界入侵自动监测摄像机作为安全监控领域的重要创新&#xff0c;正逐渐成为各类场所安全防范的核心设备。这种摄像机以其先进的监测和预警功能&#xff0c;有效提升了安全管理的效率和实时响应能力&#xff0c;被广泛应用于各类…

什么是屎山代码?

为什么说再厉害的程序员&#xff0c;也怕屎山代码&#xff1f; 首先&#xff0c;屎山代码不是指的一种开发语言&#xff0c;而是对庞大项目的一个别称。 常言道&#xff0c;屎山传万代&#xff0c;代代不吱声。每次传承都会遗留大量问题&#xff0c;接手的人一般都不敢动代码&a…

JSONpath语法怎么用?

JSONPath 可以看作定位目标对象位置的语言&#xff0c;适用于 JSON 文档。 JSONPath 与 JSON 的 关系相当于 XPath 与 XML 的关系&#xff0c; JSONPath 参照 XPath 的路径表达式&#xff0c;提供了描述 JSON 文档层次结构的表达式&#xff0c;通过表达式对目标…

双端队列广搜——AcWing 175. 电路维修

双端队列广搜 定义 双端队列广搜&#xff08;Breadth-First Search with a Deque&#xff09;是一种图或树的遍历算法变体&#xff0c;它利用了双端队列&#xff08;Deque&#xff0c;全称Double Ended Queue&#xff0c;允许在其两端进行插入和删除操作&#xff09;作为数据…

vision mamba-yolov8:结合Vmamba的yolov8目标检测改进实现

1.vision mamba结构与原理 Mamba成功的关键在于S6模型&#xff0c;该模型为NLP任务设计&#xff0c;通过选择性扫描空间状态序列模型&#xff0c;将二次复杂度降低至线性。但由于视觉信号&#xff08;如图像&#xff09;的无序性&#xff0c;Mamba的S6模型不能直接应用&#xf…

20240701给NanoPi R6C开发板编译友善之臂的Android12系统

20240701给NanoPi R6C开发板编译友善之臂的Android12系统 2024/7/1 14:19 本文采取这个模式编译&#xff1a;11.6.3 编译Android Tablet版本(首次编译) echo "ROCKCHIP_DEVICE_DIR : device/rockchip/rk3588/nanopi6" > .rockchip_device.mk # export INSTALL_GAP…

给小程序接入AI服务之后,我的睡后收入又增加了

自从本人写了《[从零开始三天学会微信小程序开发]》教程以来&#xff0c;不断有人加我&#xff0c;一起交流微信小程序开发的事情&#xff0c;很让人开心。 也有一些人和我说&#xff0c;现在已经是AI时代了&#xff0c;怎么还用这种固定内容的模式呢&#xff1f;确实是的&…

K8S 集群节点缩容

环境说明&#xff1a; 主机名IP地址CPU/内存角色K8S版本Docker版本k8s231192.168.99.2312C4Gmaster1.23.1720.10.24k8s232192.168.99.2322C4Gwoker1.23.1720.10.24k8s233&#xff08;需下线&#xff09;192.168.99.2332C4Gwoker1.23.1720.10.24 1. K8S 集群节点缩容 当集群中有…

ROS2使用Python开发动作通信

1.创建接口节点 cd chapt4_ws/ ros2 pkg create robot_control_interfaces --build-type ament_cmake --destination-directory src --maintainer-name "joe" --maintainer-email "1027038527qq.com" mkdir -p src/robot_control_interfaces/action touch…