minio文件存储

news2024/9/21 14:39:44

文章目录

    • 参考
    • 安装与部署
    • springboot整合minio
      • pom.xml
      • application.yml
      • MinioProperties
      • MinioConfig
      • MinioApp
      • 测试基本功能
        • bucket是否存在
        • 创建bucket
        • 修改bucket的访问权限
        • 查询所有的bucket
        • 删除指定的bucket
        • 上传文件到minio
        • 查看对象的描述信息
        • 获取文件的预签名访问地址
        • 后台获取minio文件
        • 获取bucket中的所有文件
        • 移除指定的文件
      • 单文件上传
        • 可参考GetPresignedPostFormData
        • UploadSingleFileController
      • 分片上传
        • 手动示例

参考

安装与部署

springboot整合minio

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.7</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zzhua</groupId>
    <artifactId>demo-minio</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <!-- 在spring-boot-dependencies-2.6.7中限制了版本为3.14.9, 这与minio中依赖的版本不一致 -->
        <okhttp3.version>4.8.1</okhttp3.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </dependency>
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.4.5</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.68</version>
        </dependency>
    </dependencies>


</project>

application.yml

server:
  port: 9090
minio:
  accessKey: ~~~
  secretKey: ~~~
  endpoint: http://119.23.61.24:9000
  bucket: zzhua-bucket
  uploadUrl: ${minio.endpoint}/${minio.bucket}

MinioProperties

@Data
@ConfigurationProperties(prefix = "minio")
public class MinioProperties {

    private String accessKey;

    private String secretKey;

    private String endpoint;

    private String bucket;

    private String uploadUrl;

}

MinioConfig

@Configuration
@EnableConfigurationProperties(MinioProperties.class)
public class MinioConfig {

    @Autowired
    private MinioProperties minioProperties;

    @Bean
    public MinioClient minioClient() {
        MinioClient minioClient = MinioClient.builder()
                .credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey())
                .endpoint(minioProperties.getEndpoint())
                .build();
        return minioClient;
    }

}

MinioApp

@SpringBootApplication
public class MinioApp {

    public static void main(String[] args) {
        SpringApplication.run(MinioApp.class, args);
    }

}

测试基本功能

bucket是否存在
@SpringBootTest(classes = MinioApp.class)
public class TestMinioApp {

    @Autowired
    private MinioClient minioClient;
	
	@Test
	public void testBucketExists() throws Exception {
	     boolean b = minioClient.bucketExists(BucketExistsArgs.builder().bucket("test-bucket").build());
	     System.out.println(b);
	}

}
创建bucket
@Test
public void testMakeBucket() throws Exception {
    minioClient.makeBucket(MakeBucketArgs.builder().bucket("zzhua-bucket").build());
}
修改bucket的访问权限
@Test
public void testSetBucketPolicy() throws Exception {

    StringBuilder builder = new StringBuilder();
    builder.append("{\n");
    builder.append("    \"Statement\": [\n");
    builder.append("        {\n");
    builder.append("            \"Action\": [\n");
    builder.append("                \"s3:GetBucketLocation\",\n");
    builder.append("                \"s3:ListBucket\"\n");
    builder.append("            ],\n");
    builder.append("            \"Effect\": \"Allow\",\n");
    builder.append("            \"Principal\": \"*\",\n");
    builder.append("            \"Resource\": \"arn:aws:s3:::zzhua-bucket\"\n");
    builder.append("        },\n");
    builder.append("        {\n");
    builder.append("            \"Action\": \"s3:GetObject\",\n");
    builder.append("            \"Effect\": \"Allow\",\n");
    builder.append("            \"Principal\": \"*\",\n");
    builder.append("            \"Resource\": \"arn:aws:s3:::zzhua-bucket/myobject*\"\n");
    builder.append("        }\n");
    builder.append("    ],\n");
    builder.append("    \"Version\": \"2012-10-17\"\n");
    builder.append("}\n");
    minioClient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket("zzhua-bucket").config(builder.toString()).build());
}
查询所有的bucket
@Test
public void testListBucket() throws Exception {
    List<Bucket> buckets = minioClient.listBuckets();
    for (Bucket bucket : buckets) {
        System.out.println(bucket.name() + bucket.creationDate().toString());
    }
}
删除指定的bucket
@Test
public void testRemoveBucket() throws Exception {
    minioClient.removeBucket(RemoveBucketArgs.builder().bucket("test-bucket").build());
}
上传文件到minio
@Test
public void testPutObject() throws Exception {

    File file = new File("C:\\Users\\zzhua195\\Desktop\\soft-dev.png");

    ObjectWriteResponse objectWriteResponse = minioClient.putObject(PutObjectArgs.builder()
            .bucket("zzhua-bucket")
            .object(file.getName())
            .stream(new FileInputStream(file), file.length(), -1)
            .build());

    System.out.println(objectWriteResponse.etag());
    System.out.println(objectWriteResponse.versionId());
    System.out.println(objectWriteResponse);

    // 也可以用minioClient.uploadObject
}
查看对象的描述信息
@Test
 public void testStatObject() throws Exception {

     StatObjectResponse statObjectResponse = minioClient.statObject(StatObjectArgs.builder()
             .bucket("zzhua-bucket")
             .object("soft-dev.png")
             .build()
     );

     System.out.println(statObjectResponse);

 }
获取文件的预签名访问地址

@Test
public void testGetPresignedObjectUrl() throws Exception {

    // bucket如果是私有的, 那么就需要生成签名的url才能访问。如果是公有的, 那就可以直接访问。
    String presignedObjectUrl = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
            .bucket("zzhua-bucket")
            .object("soft-dev.png")
            .method(Method.GET)
            .expiry(180, TimeUnit.SECONDS) // 3分钟之后失效
            .build()
    );

    System.out.println(presignedObjectUrl);

}

后台获取minio文件
@Test
public void testGetObject() throws Exception{
    GetObjectResponse getObjectResponse = minioClient.getObject(GetObjectArgs.builder()
            .bucket("zzhua-bucket")
            .object("soft-dev.png")
            .build()
    );


    /*ByteArrayOutputStream baos = new ByteArrayOutputStream();

    byte[] bytes = new byte[1024];

    int len = 0;
    while ((len = object.read(bytes)) != -1) {
        baos.write(bytes, 0, len);
    }

    System.out.println(baos.toByteArray().length);*/
}
获取bucket中的所有文件
@Test
public void testListObjects() throws Exception{
    Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket("zzhua-bucket").build());

    for (Result<Item> result : results) {
        System.out.println(result.get().objectName());
    }

}
移除指定的文件
@Test
public void testRemoveObject() throws Exception{
    minioClient.removeObject(RemoveObjectArgs.builder()
            .bucket("zzhua-bucket")
            .object("soft-dev.png")
            .build()
    );
}

单文件上传

前端先向后端申请1个上传文件到minio的文件上传路径,返回将上文件上传到minio所需要携带的表单信息

可参考GetPresignedPostFormData
public class GetPresignedPostFormData {
    /**
     * MinioClient.presignedPostPolicy() example.
     */
    public static void main(String[] args)
            throws IOException, NoSuchAlgorithmException, InvalidKeyException {
        try {
            /* play.min.io for test and development. */
            MinioClient minioClient =
                    MinioClient.builder()
                            .endpoint("http://119.23.61.24:9000")
                            .credentials("~~~", "~~~")
                            .build();

            /* Amazon S3: */
            // MinioClient minioClient =
            //     MinioClient.builder()
            //         .endpoint("https://s3.amazonaws.com")
            //         .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY")
            //         .build();

            // Create new post policy for 'my-bucketname' with 7 days expiry from now.
            PostPolicy policy = new PostPolicy("zzhua-bucket", ZonedDateTime.now().plusHours(2));

            String objectName = "test5.png";

            // Add condition that 'key' (object name) equals to 'my-objectname'.
            policy.addEqualsCondition("key", objectName);

            // Add condition that 'Content-Type' starts with 'image/'.
            policy.addStartsWithCondition("Content-Type", "image/");

            // Add condition that 'content-length-range' is between 64kiB to 10MiB.
            policy.addContentLengthRangeCondition(64 * 1024, 10 * 1024 * 1024);

            Map<String, String> formData = minioClient.getPresignedPostFormData(policy);

            // Upload an image using POST object with form-data.
            MultipartBody.Builder multipartBuilder = new MultipartBody.Builder();
            multipartBuilder.setType(MultipartBody.FORM);
            for (Map.Entry<String, String> entry : formData.entrySet()) {
                multipartBuilder.addFormDataPart(entry.getKey(), entry.getValue());
            }
            multipartBuilder.addFormDataPart("key", objectName);
            multipartBuilder.addFormDataPart("Content-Type", "image/png");

            // "file" must be added at last.
            multipartBuilder.addFormDataPart(
                    "file", "test4.png", RequestBody.create(new File("D:\\myowrk\\Notes\\java-developer-document\\知识库\\网络安全\\kali渗透\\images\\02-Metasploit-1706781339305.png"), null));

            Request request =
                    new Request.Builder()
                            .url("http://119.23.61.24:9000/zzhua-bucket")
                            .post(multipartBuilder.build())
                            .build();
            OkHttpClient httpClient = new OkHttpClient().newBuilder().build();
            Response response = httpClient.newCall(request).execute();
            if (response.isSuccessful()) {
                System.out.println("Pictures/avatar.png is uploaded successfully using POST object");
            } else {
                System.out.println("Failed to upload Pictures/avatar.png");
            }

            // Print curl command usage to upload file /tmp/userpic.jpg.
            /*System.out.print("curl -X POST ");
            for (Map.Entry<String, String> entry : formData.entrySet()) {
                System.out.print(" -F " + entry.getKey() + "=" + entry.getValue());
            }
            System.out.print(" -F key=my-objectname -F Content-Type=image/jpg");
            System.out.println(" -F file=@/tmp/userpic.jpg https://play.min.io/my-bucketname");*/
        } catch (MinioException e) {
            System.out.println("Error occurred: " + e);
        }
    }
}

UploadSingleFileController
@Slf4j
@RestController
@RequestMapping("upload")
public class UploadSingleFileController {

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioProperties minioProperties;

    @RequestMapping("singleFile")
    public Result singleFile(@RequestParam String filename) {

        PostPolicy postPolicy = new PostPolicy(minioProperties.getBucket(), ZonedDateTime.now().plusHours(2));

        String date = DateTimeFormatter.ofPattern("yyyyMMdd").format(LocalDate.now());

		// 这里中间有斜杠, 将会在minio中创建文件夹
        String key = date + "/" + filename;

        // key的格式: {yyyyMMdd}/{filename}
        postPolicy.addEqualsCondition("key", key);

        // 后续前端上传时, 表单中指定的key必须与此处的key完全一样
        System.out.println("key: " + key);

        try {
            // A: 前端上传时的表单需要指定:
            //      1. 这里全部的formData
            //      2. key, 值为上面policy中设置的key
            //      3. file, 值为文件
            // B: 前端上传地址为: http://ip:9000/{bucket}
            // C: 前端上传之后, 访问url为: http://ip:9000/{bucket}/{key}
            Map<String, String> formData = minioClient.getPresignedPostFormData(postPolicy);
            System.out.println(JSON.toJSONString(formData));

            FileUploadDTO uploadDTO = new FileUploadDTO();
            uploadDTO.setFileName(filename);
            uploadDTO.setFormData(formData);

            uploadDTO.setUploadUrl(minioProperties.getUploadUrl());

            return Result.ok(uploadDTO);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.fail("上传失败");
        }
    }

}

在这里插入图片描述

分片上传

minio分片上传分为后端分片上传和前端分片上传。

后端分片上传:直接将文件进行分片,然后将各个分片都上传到minio中,然后合并文件,然后删除所有分片文件

前端分片上传:前端根据用户上传文件的大小决定是否要使用分片上传(minio设定是每个分片最小5M,除最后1个分片外,否则合并会报错),然后如果决定要分片,计算分片数量,然后请求后台 获得每个分片的上传地址,前端进行文件拆分并自行将文件上传到对应的路径,当所有的分片上传完成之后,再请求后台合并文件的接口,将文件合并成1个文件,后台删除所有分片文件。后台可以根据分片数量和根据前缀查询指定文件再minio对应的分片序号统计还有哪些分片没有上传完成来实现断点续传。

手动示例

第一步:将mysql.pdf拆分成2个分片,名为mysql_1.chunk(大小为:5242880)和mysql_2.chunk(大小为:2593246),后面模拟前端上传这2个文件

public class File2Chunk {

    public static void main(String[] args) throws Exception {

        File file = new File("C:\\Users\\zzhua195\\Desktop\\mysql.pdf");
        String fileNameNoExt = file.getName().substring(0, file.getName().lastIndexOf("."));

        RandomAccessFile raf = new RandomAccessFile(file, "rw");
        byte[] bytes1 = new byte[5 * 1024 * 1024];
        raf.read(bytes1);


        FileOutputStream fos1 = new FileOutputStream(file.getParent() + "/" + fileNameNoExt + "_1" + ".chunk");

        fos1.write(bytes1);
        fos1.flush();
        fos1.close();

        FileOutputStream fos2 = new FileOutputStream(file.getParent() + "/" + fileNameNoExt + "_2" + ".chunk");

        int len = 0;
        byte[] bytes = new byte[1024];
        while ((len = raf.read(bytes)) != -1) {
            fos2.write(bytes, 0, len);
        }
        fos2.flush();
        fos2.close();

    }

}

第二步:为每个分片获取对应的上传路径,要注意下:1. objectName就是分片名。 2.返回的url不能直接使用,要使用url解码。3. 对于minioClient.getPresignedObjectUrl(…)方法,设置不同的method有不同的作用

public class PresignedPutObject {
    /**
     * MinioClient.presignedPutObject() example.
     */
    public static void main(String[] args)
            throws IOException, NoSuchAlgorithmException, InvalidKeyException {
        try {
            /* play.min.io for test and development. */
            MinioClient minioClient =
                    MinioClient.builder()
                            .endpoint("http://119.23.61.24:9000")
                            .credentials("CHEsnxJpF42dWcglylTi", "xWfrqTbMFo0w2o5f8jSaYLW1XRmj8Bff3wErfboS")
                            .build();

            /* Amazon S3: */
            // MinioClient minioClient =
            //     MinioClient.builder()
            //         .endpoint("https://s3.amazonaws.com")
            //         .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY")
            //         .build();

            // Get presigned URL string to upload 'my-objectname' in 'my-bucketname'
            // with response-content-type as application/json and its life time is
            // one day.
            Map<String, String> reqParams = new HashMap<String, String>();
            reqParams.put("response-content-type", "application/json");

            String url = minioClient.getPresignedObjectUrl(
                    GetPresignedObjectUrlArgs.builder()
                            .method(Method.PUT)
                            .bucket("zzhua-bucket")
                            .object("mysql_1.chunk")
                            .expiry(60 * 60 * 24)
                            .extraQueryParams(reqParams)
                            .build());
            // System.out.println(url);

            // 注意要把这个url解码了才能正常使用
            // 然后将文件上传到这个地址上
            System.out.println(URLDecoder.decode(url, StandardCharsets.UTF_8.name()));
        } catch (MinioException e) {
            System.out.println("Error occurred: " + e);
        }
    }
}

第三步:使用postman将每个分片都上传到minio(模拟前端上传分片),由于本地使用的apiPost不支持binary上传,所有使用 网页版的ApiFox

  1. 直接将返回的url粘贴到路径处,签名参数会自动填充到params中
  2. Body使用binary,然后选择对应的分片文件(这个看到有人用put请求方式,并且使用form-data,key为file,值为文件,未试)
  3. Header中须添加Content-Length请求头,值为分片文件的大小
  4. 请求方式为PUT

上传mysql_1.chunk(如下图),然后再上传mysql_2.chunk(省略)
在这里插入图片描述
第四步:查询在minio中mysql_前缀下的对象有多少个,然后合并这些分片成1个文件,合并成功之后删除这些分片

查询指定前缀的分片

    @Test
    void name() throws Exception {

        Iterable<Result<Item>> mysql_ = minioClient.listObjects(ListObjectsArgs.builder().bucket("zzhua-bucket").prefix("mysql_").build());
        for (Result<Item> itemResult : mysql_) {
            System.out.println(itemResult.get().objectName());
        }

    }

合并文件

public class ComposeObject {
    /**
     * MinioClient.composeObject() example.
     */
    public static void main(String[] args)
            throws IOException, NoSuchAlgorithmException, InvalidKeyException {
        try {
            /* play.min.io for test and development. */
            MinioClient minioClient =
                    MinioClient.builder()
                            .endpoint("http://119.23.61.24:9000")
                            .credentials("~~~", "~~~")
                            .build();

            /* Amazon S3: */
            // MinioClient minioClient =
            //     MinioClient.builder()
            //         .endpoint("https://s3.amazonaws.com")
            //         .credentials("YOUR-ACCESSKEY", "YOUR-SECRETACCESSKEY")
            //         .build();

            // Create a ComposeSource to compose Object.
            List<ComposeSource> sources = new ArrayList<ComposeSource>();
            sources.add(
                    ComposeSource.builder()
                            .bucket("zzhua-bucket")
                            .object("mysql_1.chunk")
                            .build());
            sources.add(
                    ComposeSource.builder()
                            .bucket("zzhua-bucket")
                            .object("mysql_2.chunk")
                            .build());

            minioClient.composeObject(
                    ComposeObjectArgs.builder()
                            .bucket("zzhua-bucket")
                            .object("mysql.pdf")
                            .sources(sources)
                            .build());
            System.out.println("Object Composed successfully");

      /*{
        ServerSideEncryptionCustomerKey srcSsec =
            new ServerSideEncryptionCustomerKey(
                new SecretKeySpec(
                    "01234567890123456789012345678901".getBytes(StandardCharsets.UTF_8), "AES"));

        ServerSideEncryption sse =
            new ServerSideEncryptionCustomerKey(
                new SecretKeySpec(
                    "12345678912345678912345678912345".getBytes(StandardCharsets.UTF_8), "AES"));

        List<ComposeSource> sources = new ArrayList<ComposeSource>();
        sources.add(
            ComposeSource.builder()
                .bucket("my-bucketname")
                .object("my-objectname-one")
                .ssec(srcSsec)
                .build());
        sources.add(
            ComposeSource.builder()
                .bucket("my-bucketname")
                .object("my-objectname-two")
                .ssec(srcSsec)
                .build());

        minioClient.composeObject(
            ComposeObjectArgs.builder()
                .bucket("my-destination-bucket")
                .object("my-destination-object")
                .sources(sources)
                .sse(sse)
                .build());
        System.out.println("Object Composed successfully");
      }*/

        } catch (MinioException e) {
            System.out.println("Error occurred: " + e);
        }
    }


}

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

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

相关文章

第二课《动态规划》

1.1.1 线性dp 2.1.1 区间dp 3.1.1 背包dp 动态规划理论 动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中&#xff0c; 可能会有很多可行解。没一个解都对应于一个值&#xff0c;我们希望找到具有最优值的解。胎动规划算法与分治法类似&#xff0c;其基本思想…

数据丢失不再怕!2024年高效硬盘恢复软件精选

硬盘数据丢失或文件损坏等问题&#xff0c;这不仅会影响我们的日常工作与生活&#xff0c;还可能造成无法挽回的损失。随着技术的发展&#xff0c;市场上涌现出了众多硬盘数据恢复软件。本文将为您介绍几款主流且高效的硬盘文件修复工具&#xff0c;希望能为您在数据遭遇不测时…

《深入浅出WPF》读书笔记.6binding系统(下)

《深入浅出WPF》读书笔记.6binding系统(下) 背景 主要讲数据校验和数据转换以及multibinding 代码 binding的数据校验 <Window x:Class"BindingSysDemo.ValidationRulesDemo"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmln…

innodb_buffer_pool_size在线缩小操作

一、背景 测试数据库内存32G&#xff0c;只有MySQL数据库&#xff0c;但是innodb_buffer_pool_size设置了24G&#xff0c;导致经常出现lack of memory问题、lack of swap问题。 因为使用了MySQL5.7.36版本&#xff0c;利用innodb_buffer_pool_size参数值可在线调整的新特性&…

这个TOP 100 AI应用榜单,包含了所有你需要的使用场景(一)

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;专注于分享AI全维度知识&#xff0c;包括但不限于AI科普&#xff0c;AI工…

【源码+文档+调试讲解】劳务外包管理系统的设计与实现

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对劳务外包信息管理混乱&#xff0c;出错率高&#xff0c;信息安全性差…

微分方程(Blanchard Differential Equations 4th)中文版Section3.7

迹-行列式平面上平面系统分析 在前面的章节中,我们遇到了许多不同类型的线性微分方程系统。到目前为止,可能会觉得这些系统有很多不同的可能性,每种都有其独特的特征。为了将这些例子放在整体视角下进行回顾,创建一个表格是一个有用的方法。 总结我们到目前为止所做的工作…

基于SHAP进行特征选择和贡献度计算——可解释性机器学习

方法介绍 SHAP&#xff08;SHapley Additive exPlanations&#xff09;是一个 Python 包&#xff0c;旨在解释任何机器学习模型的输出。SHAP 的名称源自合作博弈论中的 Shapley 值&#xff0c;它构建了一个加性的解释模型&#xff0c;将所有特征视为“贡献者”。对于每个预测样…

深入探讨量子计算领域的最新进展及其对社会经济的影响

一、引言 在21世纪的科技浪潮中&#xff0c;量子计算作为一项颠覆性技术&#xff0c;正逐步从理论走向实践&#xff0c;成为各国竞相争夺的科技制高点。量子计算利用量子力学原理&#xff0c;实现了对传统计算模式的根本性变革&#xff0c;其强大的并行处理能力和指数级增长的…

如何正确使用 Parallels Desktop 的快照功能

在 Parallels Desktop for Mac 中&#xff0c;快照&#xff08;Snapshot&#xff09;功能非常实用&#xff0c;特别是当你需要在不同的状态之间自由切换&#xff0c;或是想要在实验或测试前备份虚拟机状态时。以下是使用快照功能的详细步骤和注意事项&#xff1a; 注意 在 Ap…

基于x86_64系统构建并运行aarch64架构docker镜像

基于x86_64系统构建并运行aarch64架构docker镜像 1.安装qemu模拟器2.编写Dockerfile3.查看镜像架构4.启动容器 1.安装qemu模拟器 docker run --privileged --rm tonistiigi/binfmt --install all如果出现invalid argument等信息&#xff0c;表示qemu安装失败。可能是内核版本问…

python读取csv,中文输出乱码的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

基于51单片机的百叶窗proteus仿真

地址&#xff1a;https://pan.baidu.com/s/19M6jeTIHJcyDBGNx4H9nTA 提取码&#xff1a;1234 仿真图&#xff1a; 芯片/模块的特点&#xff1a; AT89C52/AT89C51简介&#xff1a; AT89C52/AT89C51是一款经典的8位单片机&#xff0c;是意法半导体&#xff08;STMicroelectron…

从最浅层剖析C语言——第四节(超详细讲解一维数组内容)

目录 1. 数组的概念 2. 一维数组的创建及其初始化 2.1 数组的创建 2.2 数组的初始化 考点总结&#xff1a;当我们未对数组进行初始化时&#xff0c;数组里面的元素打印出来是乱码&#xff0c;但哪怕只对数组里面一个元素赋值&#xff0c;之后未被赋值的元素也会默认赋值为…

Dijkstra(c++)

迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959年提出的&#xff0c;因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法&#xff0c;解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始&#xff0c;采用贪心算法的策略&#…

《晶核》服务器架构——第二篇

继上面的第一篇文章&#xff0c;没看的可以翻一下。还是进程数量多的问题&#xff1f; 副本问题怎么解决&#xff1f;服务器该如何设计&#xff1f; 按照他们这个做法是副本与场景都是地图&#xff0c;所以就造成了下面这样的问题。假如&#xff0c;我有1万人的在线数量&…

从源码开始:在线教育系统与网校APP的架构设计与开发实践

这篇文章将从源码层面探讨在线教育系统与网校APP的架构设计与开发实践&#xff0c;帮助开发者理解核心技术与实现路径&#xff0c;进而打造功能全面、性能优异的在线教育平台。 一、在线教育系统的核心功能模块 在设计在线教育系统时&#xff0c;首先需要明确其核心功能模块。…

PCL区域生长分割

文章目录 一、算法原理1、输入2、初始化3、算法二、代码部分三、代码解释参考文献本文,我们将学习如何使用 pcl::RegionGrowing 类中实现的区域生长算法。该算法的目的是合并在平滑度约束方面足够接近的点。因此,该算法的输出是簇的集合,其中每个簇被认为是同一光滑表面的一…

NASA:北极辐射-冰桥海冰实验(ARISE)2014年原地云数据产品

ARISE_Cloud_AircraftInSitu_C130_Data 简介 ARISE_Cloud_AircraftInSitu_C130_Data_1是北极辐射-冰桥海冰实验&#xff08;ARISE&#xff09;2014年原地云数据产品。该产品是位于华盛顿的美国宇航局科学任务局地球科学部辐射科学、冰冻层科学和机载科学计划共同努力的成果。…

Mysql高可用之组复制 (MGR)从原理到实战一篇解决

一&#xff1a;原理 简介&#xff1a; MySQL Group Replication(简称 MGR )是 MySQL 官方于 2016 年 12 月推出的一个全新的高可用与高扩展的解决方案。 组复制是 MySQL 5.7.17 版本出现的新特性&#xff0c;它提供了高可用、高扩展、高可靠的 MySQL 集群服务 MySQL 组复制分…