关于minio的简单使用

news2024/11/16 18:42:59

最近在学习minio相关知识,小小的记录一下学习内容

MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。

MinIO是一个非常轻量的服务,可以很简单的和其他应用的结合,类似 NodeJS, Redis 或者 MySQL。目前支持JavaScript 、Java、Python、Golang、.NET。

官网:https://min.io/    中文文档:http://www.minio.org.cn/

源码地址:https://github.com/minio/minio

由于使用的是windows10的电脑,因此下载的是windows版本的可查考官方提供文档进行操作https://min.io/download#/windows 

也可以直接下载可执行exehttps://dl.min.io/server/minio/release/windows-amd64/minio.exe

下载完成后不要不要双击minio.exe文件,在存放minio.exe文件夹中新建一个minioData文件夹,用来储存minio上传的文件目录,在地址栏里输入cmd按下回车键输入minio.exe server E:\minio\minioData(启动minio的命令)

 

 至此就可以在浏览器上进行创建bucket,文件的上传、下载、删除等一系列操作了。

使用springboot进行minio的相关操作,首先需要添加minio依耐

<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.5.4</version>
</dependency>

 在yml或properties进行minio配置

minio:
  endpoint: http://192.168.1.102:9000 #Minio服务所在地址
  bucketName: test #存储桶名称(文件夹名称)
  accessKey: minioadmin #访问的key(类似用户名)
  secretKey: minioadmin #访问的秘钥(类似密码)

minio基本配置

@Component
@ConfigurationProperties(prefix = "minio")
@Data
public class MinioProperties {
    private String endpoint;
    private String bucketName;
    private String accessKey;
    private String secretKey;

}

简单的上传、下载文件及压缩包、查询列表等访问操作

@Slf4j
@RestController
@RequestMapping("/minio")
public class MinioController {
    @Autowired
    private MinioClient minioClient;
    
    @Autowired
    private MinioProperties minioProperties;

    private List<String> docList = new ArrayList<>();

    /**
     * 获取文件列表
     * @param map
     * @return
     * @throws Exception
     */
    @GetMapping("/list")
    public List<Object> list(ModelMap map) throws Exception {
        ListObjectsArgs listObjectsArgs = ListObjectsArgs.builder().bucket(minioProperties.getBucketName()).build();
        Iterable<Result<Item>> myObjects = minioClient.listObjects(listObjectsArgs);
//        Iterable<Result<Item>> myObjects = minioClient.listObjects(minioProperties.getBucketName());
        Iterator<Result<Item>> iterator = myObjects.iterator();
        List<Object> items = new ArrayList<>();
        String format = "{'fileName':'%s','fileSize':'%s'}";
        while (iterator.hasNext()) {
            Item item = iterator.next().get();
            items.add(JSON.parse(String.format(format, item.objectName(), formatFileSize(item.size()))));
        }
        return items;
    }

    /**
     * 查看所有的上传文件列表
     * @param pageNum
     * @param pageSize
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping(value = "/fileList", method = RequestMethod.GET, produces = {"application/json;charset=utf-8"})
    public String getFileList(Integer pageNum, Integer pageSize) throws Exception {
        List<Bucket> buckets = minioClient.listBuckets();
        List<FileVo> list = new ArrayList<>();
        if (!buckets.isEmpty()) {
            for (int i = 0; i < buckets.size(); i++) {
                Bucket s = buckets.get(i);
                listDocs(s.name(),"", list);
            }
        }
        JSONObject res = new JSONObject();
        res.put("code", 200);
        res.put("message", "获取文件列表成功");
        // 按最后上传时间排序
        list.sort(new Comparator<FileVo>() {
            @Override
            public int compare(FileVo o1, FileVo o2) {
                return o2.getUpdateTime().compareTo(o1.getUpdateTime());
            }
        });
        // 分页
        List returnList = PageUtil.startPage(list, pageNum, pageSize);
        res.put("list", returnList);
        ObjectMapper mapper = new ObjectMapper();
        String s = mapper.writeValueAsString(res);
        return s;
    }

    public void listDocs(String bucketName,String prefix, List<FileVo> list){
        DecimalFormat df = new DecimalFormat("0.00");
        Iterable<Result<Item>> listObjects=new ArrayList<>();
        if(StringUtils.hasLength(prefix)){
            listObjects = minioClient.listObjects(ListObjectsArgs.builder()
                    .bucket(bucketName)
                    .prefix(prefix)
                    .build());
        }else {
            listObjects = minioClient.listObjects(ListObjectsArgs.builder()
                    .bucket(bucketName)
                    .build());
        }
        try{
            for (Result<Item> result : listObjects) {
                Item item = result.get();
                if(item.isDir()){
                    docList.add(item.objectName());
                    listDocs(bucketName,item.objectName(),list);
                }else{
                    FileVo fileVo = new FileVo();
                    fileVo.setBucketName(bucketName);  // 文件夹名称
                    String name = URLDecoder.decode(item.objectName(),"utf-8");
                    fileVo.setFileName(name);  // 文件名称
                    fileVo.setUpdateTime(localDateTime2Date(item.lastModified().toLocalDateTime()));  // 文件上传时间
                    Long size = item.size();
                    if (size > (1024 * 1024)) {
                        fileVo.setFileSize(df.format(((double) size / 1024 / 1024)) + "MB");  // 文件大小,如果超过1M,则把单位换成MB
                    } else if (size > 1024) {
                        fileVo.setFileSize(df.format(((double) size / 1024)) + "KB"); // 文件大小,如果没超过1M但是超过1000字节,则把单位换成KB
                    } else {
                        fileVo.setFileSize(size + "bytes");  // // 文件大小,如果没超过1000字节,则把单位换成bytes
                    }
                    list.add(fileVo);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public Iterable<Result<Item>> listObjects(String bucketName,String prefix,String title,boolean recursive){
        try {
            Iterable<Result<Item>> listObjects=new ArrayList<>();
            if(StringUtils.hasLength(title)){
                listObjects = minioClient.listObjects(ListObjectsArgs.builder()
                        .bucket(bucketName)
                        .prefix(prefix)
                        .startAfter(title)
                        .build());
            }
            else if(StringUtils.hasLength(prefix)){
                listObjects = minioClient.listObjects(ListObjectsArgs.builder()
                        .bucket(bucketName)
                        .prefix(prefix)
                        .recursive(recursive) // 递归
                        .build());
            }else {
                listObjects = minioClient.listObjects(ListObjectsArgs.builder()
                        .bucket(bucketName)
                        .recursive(recursive) // 递归
                        .build());
            }
            return listObjects;
        } catch (Exception e) {
            System.out.println("Error occurred: " + e);
            e.printStackTrace();
            return null;
        }
    }

    public Date localDateTime2Date( LocalDateTime localDateTime){
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = localDateTime.atZone(zoneId);
        Date date = Date.from(zdt.toInstant());
        Calendar cal=Calendar.getInstance();
        cal.setTime(date);
        // 由于获取的时间存在时间差,我这里手动加上16小时
        cal.add(Calendar.HOUR_OF_DAY, 16);
        date = cal.getTime();
        return date;
    }


    /**
     * 上传文件
     * @param file 要上传的文件
     * @return
     */
    @PostMapping("/upload")
    public Res upload(@RequestParam(name = "file", required = false) MultipartFile[] file) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException, RegionConflictException, ServerException {
        Res res = new Res();
        res.setCode(500);

        if (file == null || file.length == 0) {
            res.setMessage("上传文件不能为空");
            return res;
        }

        //存入bucket不存在则创建,并设置为只读
        if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(minioProperties.getBucketName()).build())){
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(minioProperties.getBucketName()).build());
//        if (!minioClient.bucketExists(minioProperties.getBucketName())) {
//            minioClient.makeBucket(minioProperties.getBucketName());
            //minioClient.setBucketPolicy(minioProperties.getBucketName(), "*.*", PolicyType.READ_ONLY);
        }

        List<String> orgfileNameList = new ArrayList<>(file.length);

        for (MultipartFile multipartFile : file) {
            // 获取真实文件名
            String orgfileName = multipartFile.getOriginalFilename();
            // 父目录名
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            // 文件存储的目录结构
            String objectName = sdf.format(new Date()) + "/" + orgfileName;

            try {
                InputStream in = multipartFile.getInputStream();
                // 开始上传
                PutObjectArgs objectArgs = PutObjectArgs.builder().object(objectName).bucket(minioProperties.getBucketName()).contentType("application/octet-stream").stream(in,in.available(),-1).build();
                minioClient.putObject(objectArgs);
//                minioClient.putObject(minioProperties.getBucketName(), objectName, in, new PutObjectOptions(in.available(), -1));
                in.close();
                // 完成上传以后再保存文件完整路径
                String fullFilePath = minioProperties.getEndpoint() + "/" + minioProperties.getBucketName() + "/" + objectName;
                orgfileNameList.add(fullFilePath);
            } catch (Exception e) {
                log.error(e.getMessage());
                res.setMessage("上传失败");
                return res;
            }
        }

        Map<String, Object> data = new HashMap<String, Object>();
        data.put("bucketName", minioProperties.getBucketName());
        data.put("fileName", orgfileNameList);
        res.setCode(200);
        res.setMessage("上传成功");
        res.setData(data);
        return res;
    }

    /**
     * 将指定文件以压缩包下载
     * @param response
     * @param fileName 要下载的文件名
     */
    @RequestMapping("/downLoadZip")
    public void downLoadZip(HttpServletResponse response, @RequestParam("fileName") String fileName){
        ZipOutputStream zipos = null;
        DataOutputStream os = null;
        InputStream is = null;
        try {
            response.reset();
            String zipName = new String(URLEncoder.encode(fileName, "UTF-8").getBytes(), StandardCharsets.ISO_8859_1);
            response.setHeader("Content-Disposition", "attachment;fileName=\"" + zipName + ".zip\"");
            response.setContentType("application/octet-stream; charset=UTF-8");
            zipos = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
            zipos.setMethod(ZipOutputStream.DEFLATED); //设置压缩方法
            try {
                zipos.putNextEntry(new ZipEntry(fileName));
                os = new DataOutputStream(zipos);
                GetObjectArgs getObjectArgs = GetObjectArgs.builder().object(fileName).bucket(minioProperties.getBucketName()).build();
                is = minioClient.getObject(getObjectArgs);
//                is = minioClient.getObject(minioProperties.getBucketName(), fileName);
                byte[] b = new byte[1024];
                int length = 0;
                while((length = is.read(b))!= -1){
                    os.write(b, 0, length);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            is.close();
            os.flush();
            os.close();
            zipos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (is != null) {
                try {
                    is.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (zipos != null) {
                try {
                    zipos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 将bucket下所有文件以压缩包下载
     * @param response
     * @param bucket 要下载的bucket
     */
    @RequestMapping("/batchDownLoadZip")
    public void batchDownLoadZip(HttpServletResponse response, @RequestParam("bucket") String bucket) {
        List<String> filePaths = new ArrayList<>();
        listZips(bucket,"2023",filePaths);
        ZipOutputStream zipos = null;
        DataOutputStream os = null;
        InputStream is = null;
        try {
            response.reset();
            String zipName = new String(URLEncoder.encode(bucket, "UTF-8").getBytes(), StandardCharsets.ISO_8859_1);
            response.setHeader("Content-Disposition", "attachment;fileName=\"" + zipName + ".zip\"");
            response.setContentType("application/octet-stream; charset=UTF-8");
            zipos = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
            zipos.setMethod(ZipOutputStream.DEFLATED); //设置压缩方法
            for(int i = 0;i < filePaths.size();i++) {
                String file = filePaths.get(i);
                String packageName = filePaths.get(i).replace(bucket+"/", "");
                try {
                    zipos.putNextEntry(new ZipEntry(packageName));
                    os = new DataOutputStream(zipos);
                    GetObjectArgs getObjectArgs = GetObjectArgs.builder().object(file).bucket(minioProperties.getBucketName()).build();
                    is = minioClient.getObject(getObjectArgs);
                    byte[] b = new byte[1024];
                    int length = 0;
                    while((length = is.read(b))!= -1){
                        os.write(b, 0, length);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            is.close();
            os.flush();
            os.close();
            zipos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (is != null) {
                try {
                    is.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (zipos != null) {
                try {
                    zipos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 遍历bucket下所有文件名
     * @param bucketName 要下载的bucket
     * @param prefix 前缀
     * @param filePaths 文件名列表
     */
    public void listZips(String bucketName,String prefix, List<String> filePaths){
        Iterable<Result<Item>> listObjects=new ArrayList<>();
        if(StringUtils.hasLength(prefix)){
            listObjects = minioClient.listObjects(ListObjectsArgs.builder()
                    .bucket(bucketName)
                    .prefix(prefix)
                    .build());
        }else {
            listObjects = minioClient.listObjects(ListObjectsArgs.builder()
                    .bucket(bucketName)
                    .build());
        }
        try{
            for (Result<Item> result : listObjects) {
                Item item = result.get();
                if(item.isDir()){
                    listZips(bucketName,item.objectName(),filePaths);
                }else{
                    String name = URLDecoder.decode(item.objectName(),"utf-8");
                    filePaths.add(name);  // 文件名称
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 下载指定文件
     * @param response
     * @param fileName 要下载的文件名
     */
    @RequestMapping("/download")
    public void download(HttpServletResponse response, @RequestParam("fileName") String fileName) {
        InputStream in = null;
        try {
            String name = "";
            //文件名截取
            if(fileName.lastIndexOf("/") != -1 ){
                name = fileName.substring(fileName.lastIndexOf("/") + 1);
            }else{
                name = fileName;
            }
            StatObjectArgs statObjectArgs = StatObjectArgs.builder().object(fileName).bucket(minioProperties.getBucketName()).build();
//            ObjectStat stat = minioClient.statObject(minioProperties.getBucketName(), fileName);
            ObjectStat stat = minioClient.statObject(statObjectArgs);
            response.setContentType(stat.contentType());
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(name, "UTF-8"));

            GetObjectArgs getObjectArgs = GetObjectArgs.builder().object(fileName).bucket(minioProperties.getBucketName()).build();
//            in = minioClient.getObject(minioProperties.getBucketName(), fileName);
            in = minioClient.getObject(getObjectArgs);
            IOUtils.copy(in, response.getOutputStream());

        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    log.error(e.getMessage());
                }
            }
        }
    }

    /**
     * 删除文件
     * @param fileName 要删除的文件名
     * @return
     */
    @DeleteMapping("/delete")
    public Res delete(@RequestParam("fileName") String fileName) {
        Res res = new Res();
        res.setCode(200);
        try {
            RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().object(fileName).bucket(minioProperties.getBucketName()).build();
            minioClient.removeObject(removeObjectArgs);
//            minioClient.removeObject(minioProperties.getBucketName(), fileName);
        } catch (Exception e) {
            res.setCode(500);
            log.error(e.getMessage());
        }
        return res;
    }


    /**
     * 生成可以预览的文件链接
     * @return
     * @throws XmlParserException
     * @throws NoSuchAlgorithmException
     * @throws InsufficientDataException
     * @throws InternalException
     * @throws InvalidResponseException
     * @throws InvalidKeyException
     * @throws InvalidBucketNameException
     * @throws ErrorResponseException
     * @throws IOException
     * @throws InvalidExpiresRangeException
     */
    @GetMapping("/previewList")
    public List<Object> getPreviewList() throws XmlParserException, NoSuchAlgorithmException, InsufficientDataException, InternalException, InvalidResponseException, InvalidKeyException, InvalidBucketNameException, ErrorResponseException, IOException, InvalidExpiresRangeException, ServerException {
        ListObjectsArgs listObjectsArgs = ListObjectsArgs.builder().bucket(minioProperties.getBucketName()).build();
        Iterable<Result<Item>> myObjects = minioClient.listObjects(listObjectsArgs);
//        Iterable<Result<Item>> myObjects = minioClient.listObjects(minioProperties.getBucketName());
        Iterator<Result<Item>> iterator = myObjects.iterator();
        List<Object> items = new ArrayList<>();
        String format = "{'fileName':'%s'}";
        while (iterator.hasNext()) {
            Item item = iterator.next().get();
            // TODO 根据文件后缀名,过滤哪些是可以预览的文件
            //String bucketName, 桶名称
            // String objectName, 文件路径
            // Integer expires, 链接过期时间
            // Map<String, String> reqParams 请求参数
            // 开始生成
            String filePath = minioClient.presignedGetObject(minioProperties.getBucketName(), item.objectName());
            items.add(JSON.parse(String.format(format, filePath)));
        }
        return  items;
    }



    /**
     * 显示文件大小信息单位
     * @param fileS
     * @return
     */
    private static String formatFileSize(long fileS) {
        DecimalFormat df = new DecimalFormat("#.00");
        String fileSizeString = "";
        String wrongSize = "0B";
        if (fileS == 0) {
            return wrongSize;
        }
        if (fileS < 1024) {
            fileSizeString = df.format((double) fileS) + " B";
        } else if (fileS < 1048576) {
            fileSizeString = df.format((double) fileS / 1024) + " KB";
        } else if (fileS < 1073741824) {
            fileSizeString = df.format((double) fileS / 1048576) + " MB";
        } else {
            fileSizeString = df.format((double) fileS / 1073741824) + " GB";
        }
        return fileSizeString;
    }
}

​​​​​​​

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

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

相关文章

【自动化测试】Selenium IDE脚本编辑与操作

之前&#xff0c;我们录制脚本时是录制鼠标和键盘的所有在浏览器的操作&#xff0c;那么脚本会出现多余的步骤&#xff0c;有时候我们需要手动填写脚本或修改脚本&#xff0c;所以我们有必要对selenium IDE脚本编辑与操作有所了解&#xff1b;&#xff08;采用录制的方式很容易…

如何解决大数据下滚动页面卡顿问题

原文合集地址如下&#xff0c;有需要的朋友可以关注 本文地址 合集地址 前言 之前遇到不分页直接获取到全部数据&#xff0c;前端滚动查看数据&#xff0c;页面就听卡顿的&#xff0c;当然这和电脑浏览器性能啥的还是有点关系。但根源还是一次性渲染数据过多导致的&#xf…

【Git】初始化仓库配置与本地仓库提交流程

目录 一、仓库配置邮箱与用户名 二、本地仓库提交流程 一、仓库配置邮箱与用户名 【Git】Linux服务器Centos环境下安装Git与创建本地仓库_centos git仓库搭建_1373i的博客-CSDN博客https://blog.csdn.net/qq_61903414/article/details/131260033?spm1001.2014.3001.5501 在…

JavaScript基础篇(61-70题)

此文章&#xff0c;来源于印客学院的资料【第一部分&#xff1a;基础篇(105题)】&#xff0c;也有一些从网上查找的补充。 这里只是分享&#xff0c;便于学习。 诸君可以根据自己实际情况&#xff0c;自行衡量&#xff0c;看看哪里需要加强。 概述如下&#xff1a; 希望获取…

2023年深圳杯A题赛题详细解析1.1版本

A题 影响城市居民身体健康的因素分析 附件A1是某市卫生健康研究部门对部分居民所做的“慢性非传染性疾病及其相关影响因素流行病学”调查问卷表&#xff0c;附件A2是相应的调查数据结果&#xff0c;附件A3是中国营养学会最新修订的《中国居民膳食指南》中为平衡居民膳食提出的…

UG NX二次开发(C#)-参数化修改三维模型中的文字

文章目录 1、前言2、在UG NX中创建一个带文字的三维模型3、创建一个UI界面4、 NXOpen二次开发实现5、测试1、前言 在UG NX中通过表达式不仅能修改尺寸参数、位置参数,也能修改文字,通过设计一个UI 界面,使得文字根据输入值的变化而变化,本文就针对三维模型中得文字来讲一下…

LeakCanary内存泄漏检测框架分析。

一、什么叫内存泄漏、内存溢出&#xff1f; 内存溢出(out of memory)&#xff1a;是指程序在申请内存时&#xff0c;没有足够的内存空间供其使用&#xff0c;出现out of memory&#xff1b;比如申请了一个integer,但给它存了long才能存下的数&#xff0c;那就是内存溢出。 内…

JavaEE——Bean的生命周期

目录 1、实例化Bean 2、设置Bean的属性 3、初始化Bean &#xff08;1&#xff09;、执行通知 &#xff08;2&#xff09;、初始化的前置方法 &#xff08;3&#xff09;、初始化方法 &#xff08;4&#xff09;、执行自定义方法 &#xff08;5&#xff09;、初始化的后置…

js读取接口返回的最快的那一个

promise.race 顾名思义&#xff0c;Promse.race就是赛跑的意思&#xff0c;意思就是说&#xff0c;Promise.race([p1, p2, p3])里面哪个结果获得的快&#xff0c;就返回那个结果&#xff0c;不管结果本身是成功状态还是失败状态。 Promise.race([this.$axios.get("api/on…

UiPath-TTS

UiPath-Text to Speech既TTS应用 缘起原理法一 - Invoke Method法二 - Invoke Code 总结 缘起 不知道大家有没有使用过Excel的Read Cell功能或者智能音箱&#xff0c;实用性因场景而异&#xff0c;但是很好玩。回到RPA应用中&#xff0c;大家想象一下&#xff0c;如果你给自己…

STM32的CAN外设简介

目录 STM32的CAN外设简介 CAN框图剖析 CAN控制内核 工作模式 位时序及波特率 CAN发送邮箱 CAN接收FIFO 验收筛选器&#xff08;重点&#xff09; 整体控制逻辑 STM32的CAN外设简介 STM32的芯片中具有bxCAN控制器 (Basic Extended CAN 基本扩展CAN外设)&#xff0c;它支…

executor.CoarseGrainedExecutorBackend: RECEIVED SIGNAL TERM

Bug现象 spark程序运行正常,但是查看web ui的时候如下图所示: 查看executor logs发现: ERROR executor.CoarseGrainedExecutorBackend: RECEIVED SIGNAL TERM原因分析 首先程序能够正常运行,只是发现某些executor状态为Dead了,说明该executor被移除了,至于为什么会被…

代码随想录算法训练营第二天| 977

977. 有序数组的平方y 思路&#xff0c;原数组是有序的&#xff0c;但是因为负数平方后可能变无序了&#xff0c;因此利用双指针遍历原数组&#xff0c;比较 nums[left]*nums[left]和nums[right]*nums[right]谁更大&#xff0c;然后对新数组赋值 class Solution {public int…

爬虫003_pycharm的安装以及使用_以及python脚本模版设置---python工作笔记021

这里我们用ide,pycharm来编码,看一看如何下载 这里我们下载这个社区办,这个是免费的,个人版是收费的 然后勾选以后 安装以后我们来创建一个项目 这里可以选择python的解释器,选择右边的... 这里我们找到我们自己安装的python解释器

SpringBoot——数据层三组件之间的关系

简单介绍 在之前的文章中&#xff0c;我们介绍了一下SpringBoot中内置的几种数据层的解决方案&#xff0c;在数据层由三部分组成&#xff0c;分别是数据库&#xff0c;持久化技术以及数据源&#xff0c;但是我今天写着写着&#xff0c;突然就想不起来这三部分到底是干什么的了…

助你丝滑过度到 Vue3 生命自定义hooktoRef ②⑥

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; VUE3~TS &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &#x1f449;…

TCP状态转换图

TCP状态转换图 了解TCP状态转换图可以帮助开发人员查找问题. 说明: 上图中粗线表示主动方, 虚线表示被动方, 细线部分表示一些特殊情况, 了解即可, 不必深入研究. 对于建立连接的过程客户端属于主动方, 服务端属于被动接受方(图的上半部分) 而对于关闭(图的下半部分), 服务端…

JVM内存的变化

我举得&#xff0c;从空间的角度去理解java的运行&#xff0c;能更深刻的帮助我们学习后面“面向对象”的知识。因此&#xff0c;单独拿出一章&#xff0c;来解释内存的变化。以程序为实例进行判断。 需要一点JVM运行时的内存状态知识点基础。 参考博客&#xff1a; 这种是不…

ubuntu20.04 安装 Qt5.15

目录 安装前工作 选择安装QT的哪个版本 安装时候选择哪些组件 安装Qt5.15 在线安装 我选择的组件 源码包安装 测试 安装前工作 ubuntu20.04.3安装Qt6.22操作步骤_ubuntu安装qt6_sonicss的博客-CSDN博客 # 安装g、gcc编译器 sudo apt-get install build-essential 安装l…

leetcode 455. 分发饼干

2023.7.27 今天起福州要刮台风了&#xff0c;不过还是在宿舍坚持每日一题。 今天开始刷的系列属于贪心算法系列。本题是贪心算法的一个入门题。 贪心算法总体思路就是先找局部最优&#xff0c;在一步步的找出全局最优。 本题很明显全局最优就是 需要尽可能多投喂更多的孩子。…