Java使用Opencv进行大图找小图并使用其找图功能进行bilibili视频下载案例

news2024/11/19 15:13:36

Java使用Opencv进行大图找小图并使用其找图功能进行bilibili视频下载案例

  • 一、Opencv大图找小图说明
  • 二、Opencv的window安装
    • 1.下载windows下的安装包
    • 2.安装
    • 3.Java中Opencv加载测试
  • 三、Java中通过Opencv进行模板匹配大图找小图
  • 四、进行多图查找
  • 五:案例下载bilibili视频
    • 1.bilibili网站安装下载视频插件
    • 2.业务流程分析
    • 3.代码实现
    • 3.0 先截需要的几个图
    • 3.1代码片段
    • 3.2 程序效果截图
    • 3.3 源码下载


本文将介绍Opencv在windows下的安装,并使用Java操作Opencv进行行大图找小图测试,最后通过应用大图找小图功能来实现bilibili的视频下载。

一、Opencv大图找小图说明

以下来自chatGpt3.5模型的回答:

Opencv是一款开源的计算机视觉库,可以用于图像处理、目标检测、人脸识别等领域。在Opencv中,可以使用模板匹配算法来实现大图找小图的功能。
模板匹配算法是一种基于像素级别的匹配算法,它的基本思想是在大图中寻找与小图相似的区域。具体实现过程如下:

读取大图和小图,并将它们转换为灰度图像。
定义一个滑动窗口,在大图中滑动,并将窗口中的像素与小图进行比较。
计算窗口中像素与小图像素的差异,得到一个匹配度。
将匹配度保存到一个矩阵中,矩阵的大小与大图相同。
在矩阵中找到最大匹配度的位置,即为小图在大图中的位置。
Opencv提供了多种模板匹配算法,包括平方差匹配、归一化平方差匹配、相关匹配和归一化相关匹配等。不同的算法适用于不同的场景,需要根据实际情况选择合适的算法。

总之,Opencv提供了强大的图像处理功能,可以实现大图找小图等多种应用。

二、Opencv的window安装

1.下载windows下的安装包

官网的路径是:https://opencv.org/
我下载的是4.2.0,下载地址(官网)为:https://udomain.dl.sourceforge.net/project/opencvlibrary/4.2.0/opencv-4.2.0-vc14_vc15.exe
或者链接(非官网,速度快些):https://nchc.dl.sourceforge.net/project/opencvlibrary/4.2.0/opencv-4.2.0-vc14_vc15.exe

2.安装

双击opencv-4.2.0-vc14_vc15.exe安装即可,我这里安装到D:\ProgramFiles\opencv
安装后的目录如:
在这里插入图片描述

3.Java中Opencv加载测试

引入opencv-420.jar包:
新建一个Java的maven工程,然后将安装目录下的build\java\opencv-420.jar复制到工程的lib目录
在这里插入图片描述
pom.xml中采用本地引入方式如下:

		<!-- opencv start -->
		<dependency>
			<groupId>cn.gzsendi</groupId>
			<artifactId>opencv-420</artifactId>
			<version>0.0.1</version>
			<scope>system</scope>
			<systemPath>${pom.basedir}/lib/opencv-420.jar</systemPath>
		</dependency>
		<!-- opencv end -->

build\java\x64\opencv_java420.dll放在java工程的resoure目录下
在这里插入图片描述

代码测试加载Opencv是否正常

package cn.lihua;
import java.net.URL;
import org.opencv.core.Mat;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;

public class OpencvTest {
		public static void main(String[] args) throws InterruptedException {
		// 加载动态库,放在资源目录下,推荐
        URL url = ClassLoader.getSystemResource("opencv_java420.dll");
        //另一种加载的方式,放在环境变量中,需要配置
		//System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        System.load(url.getPath());
        Mat source = Imgcodecs.imread("images/source.jpg");
        HighGui.imshow("测试", source);
		HighGui.waitKey();
	}
}

执行代码后,如果能打开图像,则opencv环境正常。

三、Java中通过Opencv进行模板匹配大图找小图

Java中进行大图找小图主要如下步骤:
1.导入Opencv库
2.加载图像
3.进行模板匹配
4.获取匹配结果
5.绘制匹配结果
6.显示结果
对应的代码如下:

package cn.lihua.modules.test;

import java.net.URL;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class TemplateMatchingTest {
	
	public static void main(String[] args) {
		String sourceImg = "images/source.bmp";
		String smallImg = "images/smallImg.bmp";
		new TemplateMatchingTest().templateMatching(sourceImg, smallImg);
	}
	
	public void templateMatching(String sourceImg,String smallImg) {
			
		// 1.导入Opencv库
		URL url = ClassLoader.getSystemResource("opencv_java420.dll");
		System.load(url.getPath());

		// 2.加载图像
		Mat src = Imgcodecs.imread(sourceImg);// 待匹配图片
		Mat template = Imgcodecs.imread(smallImg);// 获取匹配模板
		
		// 3.进行模板匹配
		// 创建一个输出图像
		Mat outputImage = new Mat(src.rows(), src.cols(), src.type());
		Imgproc.matchTemplate(src, template, outputImage, Imgproc.TM_CCOEFF_NORMED);

		// 4.获取匹配结果,查找最大匹配值
		Core.MinMaxLocResult result = Core.minMaxLoc(outputImage);
		Point matchLoc = result.maxLoc;
		double similarity = result.maxVal; //匹配度
		int x = (int) matchLoc.x; //小图大大图中的x坐标
		int y = (int) matchLoc.y; //小图大大图中的y坐标
		System.out.println(x + "," + y + " similarity: " + similarity);
		//将查找到的结果标上框框
		Imgproc.rectangle(src,new Point(x,y),new Point(x+template.cols(),y+template.rows()),
				new Scalar( 0, 0, 255),2,Imgproc.LINE_AA);
     
	     //5.显示结果
		HighGui.imshow("模板匹配", src);
		HighGui.waitKey();
		
	}

}

source.bmp
在这里插入图片描述
smallImg.bmp
在这里插入图片描述
模板匹配后:
在这里插入图片描述

四、进行多图查找

三步骤中的查询是将匹配上的最佳的子图返回,有时可能子图中会有多个,也希望能把所有的都返回,可以在查询到第一个后,不断的递归裁剪并继续匹配,最终返回所有的,示例代码如下

package cn.lihua.modules.test;

import java.net.URL;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

/**
 * 返回多个位置的例子
 * @author liujh
 *
 */
public class TemplateMatchingMultiResultExample {
	
	public static void main(String[] args) {
		String sourceImg = "images/big1.bmp";
		String smallImg = "images/small1.bmp";
		new TemplateMatchingMultiResultExample().templateMultiMatching(sourceImg, smallImg);
	}

	public void templateMultiMatching(String sourceImg,String smallImg) {
		
		// 1.导入Opencv库
		URL url = ClassLoader.getSystemResource("opencv_java420.dll");
		System.load(url.getPath());

		// 2.加载图像
		Mat largeImage = Imgcodecs.imread(sourceImg);//待匹配图片
		Mat smallImage = Imgcodecs.imread(smallImg);// 获取匹配模板1
		
		// 创建输出图像
        Mat outputImage = new Mat(largeImage.rows(), largeImage.cols(), largeImage.type());
        
        // 进行模板匹配
        Imgproc.matchTemplate(largeImage, smallImage, outputImage, Imgproc.TM_CCOEFF_NORMED);
        
        // 设置匹配阈值
        double threshold = 0.8;
        
        // 循环遍历所有匹配结果
        while (true) {
            // 查找最大匹配值
            Core.MinMaxLocResult result = Core.minMaxLoc(outputImage);
            Point matchLoc = result.maxLoc;
            double maxVal = result.maxVal;
            
            // 如果匹配值小于阈值,则退出循环
            if (maxVal < threshold) {
                break;
            }
            
            System.out.println(matchLoc.x + "," + matchLoc.y + " similarity: " + maxVal);
            
            // 在大图中标出匹配位置
            Imgproc.rectangle(largeImage, matchLoc, new Point(matchLoc.x + smallImage.cols(),
                    matchLoc.y + smallImage.rows()), new Scalar(0, 0, 255), 2);
            
            // 将匹配位置的值设置为0,以便下一次匹配
            Imgproc.rectangle(outputImage, matchLoc, new Point(matchLoc.x + smallImage.cols(),
                    matchLoc.y + smallImage.rows()), new Scalar(0, 0, 0), -1);
        }
		
		HighGui.imshow("模板匹配", largeImage);
		HighGui.waitKey();
		
	}
}

big.bmp
在这里插入图片描述
small.bmp
在这里插入图片描述
匹配结果:
在这里插入图片描述

五:案例下载bilibili视频

经过上面的测试后,我们具备了通过大图找小图的能力,接下来我们通过实践一下,写程序将bilibili网站的视频下载下来。

思路:
1.bilibili网站默认没有下载视频的插件,首先安装下载插件
2.手上尝试下载视频,找出下载视载可以自动化操作的步骤
3.通过大图找小图功能,并结合Java的Robot类实现自动化找到下载视频需要的对应图标和位置,然后模拟点击,达到自动下载的效果。

1.bilibili网站安装下载视频插件

上https://bilibilihelper.com/网站进行插件下载
在这里插入图片描述
在这里插入图片描述

得到bilibili-helper-u-2.5.23.8.zip离线插件包

chrome浏览器地址栏输入chrome://extensions/,开发模式勾上,拖动bilibili-helper-u-2.5.23.8.zip至浏览器进行安装
在这里插入图片描述

在这里插入图片描述
安装成功后,点一个视频看(一定需要点击播放视频)右上角会出现下载插件的小图标
在这里插入图片描述

2.业务流程分析

下载一个视频的步骤如下,可以看出来步骤是这样:
点击要下载的视频链接,点右上角的插件图标,在弹出的窗口中点击1080P高清图标,再点一下图标会出现点击下载,再点一下点击下载即可
在这里插入图片描述
所有视频链接的下载规律是:
前面P1、P2、P3、P4视频要点击的位置需要定位,第5个视频开始后面的视频要点击的位置都是和第5个视频一样,通过这个规律,我们可以将P1-P4视频的点击位置,通过大图找小图功能来定位,P5和后面的视频就直接用绝对位置定位进行点击,(其实都可以用绝对定位,但主要想演示就用一下Opencv的大图找小图功能)
在这里插入图片描述
这样经过分析后,整个视频下载的业务逻辑如下

1.将P1-P4的视频的链接截好小图,右上角插件图示、1080高清、点击下载等图标截好小图,供后面程序进行匹配使用
2.P1-P4的视频下载,通过大图找小图进行定位,通过Java的Robot类进行模拟点击实现视频下载
3.P5及以后的视频,通过直接绝对定位到屏幕位置点击进行视屏下载
4.视频最后的几个也简单通过绝对定位下载,和P5视频的位置不相同,也需要处理一下,我们通过绝对定位处理(此案例主要是为了练习opencv大图找小图,所有的下载其实都能通过绝对定位位置下载

下图为最后几集的点击,可以看到不再是和P5视屏一样的位置,需要每次向下移动一行的距离
在这里插入图片描述

3.代码实现

3.0 先截需要的几个图

在这里插入图片描述
注:程序启动前最好在你的电脑上重新截图

3.1代码片段

定义OpencvService接口用来实现大图找小图

package cn.lihua.modules.bilibili.service;

import java.util.List;

import cn.lihua.modules.bilibili.model.FindImgDto;

public interface OpencvService {

	/**
	 * 大图找小图
	 * @param bigImg
	 * @param smallImg
	 * @return
	 */
	FindImgDto templateMatching(String bigImg,String smallImg);
	
	/**
	 * 大图找小图
	 * @param bigImg
	 * @param smallImg
	 * @param thresholdValue 匹配度
	 * @return
	 */
	FindImgDto templateMatching(String bigImg,String smallImg,Double thresholdValue);
	
	/**
	 * 大图找小图,返回多个
	 * @param bigImg
	 * @param smallImg
	 * @param thresholdValue 匹配度
	 * @return
	 */
	List<FindImgDto> templateMultiMatching(String bigImg,String smallImg,Double thresholdValue);
	
	List<FindImgDto> templateMultiMatching(String bigImg,String smallImg);

}

定义BilibiliVideoDownService进行视频的下载

/**
 * 下载Bilibili视频
 * @author jxlhl
 */
public interface BilibiliVideoDownService {
	
	public void exportStart() throws Exception;

}

Robot类用于模拟移动和点击鼠标

		try {
			robot = new Robot();//核心机器人类,键盘或鼠标事件的重放执行。
		} catch (AWTException e) {
			logger.error("error",e);
		}

全屏截图,用于每次大图找小图时使用

	/**
	 * 全屏截图
	 */
	private void createScreenCapture() {

		int width = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();
		int height = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
		try {
			BufferedImage screenShotImage = robot.createScreenCapture(new Rectangle(0, 0, width, height));
			File sourceImg = new File("images/fullScreen.jpg");
			ImageIO.write(screenShotImage, "jpg", sourceImg);
		} catch (Exception e) {
			logger.error("error",e);
		}

	}

鼠标移动与点击的代码

	/*
	 * 移到指定的位置并左键点击
	 * 
	 */
	private void mouseMoveAndClick(int clientX, int clientY) throws InterruptedException{
		mouseMove(clientX, clientY);
		robot.delay(1000);//随即休眠0-2秒
		mouseClick();
	}
	
	/**
	 * 点击鼠标左键
	 * @throws InterruptedException 
	 */
	private void mouseClick() throws InterruptedException{
		robot.mousePress(InputEvent.BUTTON1_MASK);//左键
		robot.delay(100);
		robot.mouseRelease(InputEvent.BUTTON1_MASK);//左键
	}

	/**
	 * 移动鼠标到指定的坐标
	 */
	private void mouseMove(int clientX, int clientY){
		//不太明白这里为什么这样写,但这一行代码结合缩放比例可以稍微解决定位不准确的问题。
		robot.mouseMove(-1, -1);
		//我的电脑是200%,因此除以2
		String screenPercent = "200";
		double rate = Integer.parseInt(screenPercent)/100d;
		//增加一点点的随机数,防检测
		robot.mouseMove((int)(clientX/rate) , (int)(clientY/rate));
	}

下载某一个视频的逻辑代码

	/**
	 * 下载第{pageNumber}个视频
	 * @param pageNumber
	 * @param totalCount
	 * @throws Exception
	 */
	private void downLoad(int pageNumber,int totalCount) throws Exception{
		
		Thread.sleep(3000l);
		
		logger.info("开始下载第{}个视频,剩余{}个",pageNumber,(totalCount-pageNumber));
		
		//截图全屏,然后写入images/fullScreen.jpg
		createScreenCapture();
		//进行大图找小图测试
		FindImgDto findImgDto = null;
		
		//前面的4个视频,通过大图找小图定位位置
		if(pageNumber<=4){
			findImgDto = opencvService.templateMatching(fullScreen,"images/template/P"+pageNumber+".bmp");
			logger.info(JsonUtil.toJSONString(findImgDto));
			//找到的坐标点击时,x坐标向右靠100,可以点击得更中心些
			mouseMoveAndClick(findImgDto.getClientX() + 100 , findImgDto.getClientY());
			
		}else{
			
			if(pageNumber <= 195){
				//第5-第195个视频都点击和第5个视频所在的位置即可,1768,1011(你需要换成你的电脑上对应的位置)
				mouseMoveAndClick(1768,1011);
			}else{
				
				//最后5个视频特殊处理,直接定位进行点击
				//第196个视频
				if(pageNumber == 196){
					mouseMoveAndClick(1768,1080);//(你需要换成你的电脑上对应的位置)
				}
				//第197个视频
				if(pageNumber == 197){
					mouseMoveAndClick(1768,1150);//(你需要换成你的电脑上对应的位置)
				}
				if(pageNumber == 198){
					mouseMoveAndClick(1768,1220);//(你需要换成你的电脑上对应的位置)
				}
				if(pageNumber == 199){
					mouseMoveAndClick(1768,1280);//(你需要换成你的电脑上对应的位置)
				}
				if(pageNumber == 200){
					mouseMoveAndClick(1768,1340);//(你需要换成你的电脑上对应的位置)
				}
				
			}
			
		}
		
		//不断等待查找右上角的下载插件图标
		findImgDto = new FindImgDto();
		while(!findImgDto.isIfFind()){
			Thread.sleep(3000l);
			createScreenCapture();
			findImgDto = opencvService.templateMatching(fullScreen,click1);
			mouseMoveAndClick(findImgDto.getClientX() , findImgDto.getClientY());
		}
		
		//不断等待查找1080高清图标
		findImgDto = new FindImgDto();
		while(!findImgDto.isIfFind()){
			Thread.sleep(3000l);
			createScreenCapture();
			findImgDto = opencvService.templateMatching(fullScreen,click2);
			mouseMoveAndClick(findImgDto.getClientX() , findImgDto.getClientY());
			robot.delay(100);
			mouseMove(findImgDto.getClientX()+300, findImgDto.getClientY());
		}
		
		//不断等待查找点击下载图标
		findImgDto = new FindImgDto();
		while(!findImgDto.isIfFind()){
			Thread.sleep(3000l);
			createScreenCapture();
			findImgDto = opencvService.templateMatching(fullScreen,click3);
			mouseMoveAndClick(findImgDto.getClientX() , findImgDto.getClientY());
			robot.delay(100);
			mouseMove(findImgDto.getClientX()+300, findImgDto.getClientY());
		}
		
		//点击下载图标后,需要再点一下右上角的插件图标复原
		findImgDto = new FindImgDto();
		while(!findImgDto.isIfFind()){
			Thread.sleep(3000l);
			createScreenCapture();
			findImgDto = opencvService.templateMatching(fullScreen,click1);
			mouseMoveAndClick(findImgDto.getClientX() , findImgDto.getClientY());
			robot.delay(100);
		}
		
	}

下载所有视频的逻辑代码

	public void exportStart() throws Exception {
		
		//0.下载Bilibili视频自动化操作
		logger.info("BilibiliVideoDownService Start....");
		
		//休息5秒等待程序启动了切换到下载网站页面
		Thread.sleep(5000l);
		
		//需要下载的视频数量
		int totalCount = 200;
		try {
			
			//遍历下载每一个视频
			for(int i =1 ;i<=totalCount;i++){
				downLoad(i,totalCount);
			}
			
			//阻塞判断是否下载完成
			ifFinishedDownload();

			logger.info("all completed."); 
			
		} catch (Exception e) {
			logger.error("errror",e);
		} finally {
			
		}
		
		logger.info("BilibiliVideoDownService success..");
		
	}

3.2 程序效果截图

在这里插入图片描述

3.3 源码下载

github: https://github.com/jxlhljh/opencvBilibiliDownloadTest.git
gitee: https://gitee.com/jxlhljh/opencvBilibiliDownloadTest.git

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

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

相关文章

碳排放预测模型 | Python实现基于机器学习回归分析的碳排放预测模型——随机森林、决策树、KNN 和多层感知器 (MLP) 预测分析

文章目录 效果一览文章概述研究内容环境准备源码设计KNNRandom ForestDecision TreeMLPModel Evaluation学习总结参考资料效果一览

【Android开发基础】随机点名系统(关于读取xml资源文件)

文章目录 一、引言二、设计1、读取xml2、下拉框Spinner3、随机算法 三、实施1、子元素随机&#xff08;单位&#xff1a;班级&#xff09;2、父元素随机&#xff08;单位&#xff1a;专业&#xff09;3、指定人数随机4、指定人数混合排序 四、附件 一、引言 描述&#xff1a;这…

【手撕MyBatis源码】动态SQL全流程解析

文章目录 动态SQL概述ifchoose(when、otherwise)trim&#xff08;where、set&#xff09;foreach OGNL表达式BoundSql动态SQL主流程分析SqlNodeDynamicContext源码解析StaticTextSqlNodeTextSqlNodeIfSqlNodeChooseSqlNodeForEachSqlNode 动态脚本结构动态脚本执行 SqlSourceSt…

Spring Cloud - Eureka原理、注册、搭建、应用(全过程详解)

目录 一、Eureka 注册原理 1.1、为什么要使用 Eureka 1.2、Eureka 的工作流程及原理 1.3、eureka 的作用 二、具体实现 2.1、搭建注册中心 2.2、服务注册和部署 2.2.1、user-service 服务注册 2.2.2、服务部署 2.2.3、order-service 服务注册 2.2.4、验证服务 2.3、…

java SSM 药品集中管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM 药品集中管理系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代 码和数据库&#xff0c;系统主要采…

[神经网络]迁移学习-微调

一、概述 一般的有监督迁移学习分为以下三种&#xff1a; ①将训练好的模型作为特征抽取模块&#xff08;例如以resnet进行特征提取&#xff09; ②在一个相关的任务中训练后直接后直接使用(例如gpt) ③在训练好的模型基础上进行微调 此外还有无监督学习的方式 zero-shot&#…

【集群】LVS+Keepalived群集

文章目录 前言一、Keepalived的概念1. Keepalived 概述2. Keepalived 作用3. Keepalived 实现原理剖析3.1 Keepalived 工作原理3.1 VRRP协议&#xff08;虚拟路由冗余协议&#xff09; 4. Keepalived 主要模块及其作用4.1 健康检查方式&#xff08;学名&#xff1a;探针&#x…

【架构基础】正交设计四原则

数学中的正交&#xff0c;是指相互垂直的两个向量&#xff0c;简单来讲就是平面上的两个垂直线段&#xff0c;其中一个线段变长或减短或者转圈圈&#xff0c;另外一根是不变的也不影响它们的垂直度的。表现为空间的独立性&#xff0c;在软件中我们可以理解为两个只有交叉点而互…

springboot0+java+vuie个人家庭财务理财系统

。本文介绍了个人理财系统的开发全过程。通过分析个人理财系统管理的不足&#xff0c;创建了一个计算机管理个人理财系统的方案。文章介绍了个人理财系统的系统分析部分&#xff0c;包括可行性分析等&#xff0c;系统设计部分主要介绍了系统功能设计和数据库设计。 本个人理财系…

【数据湖架构】在 Azure Data Lake Storage (ADLS)二代上构建数据湖

介绍 一开始&#xff0c;规划数据湖似乎是一项艰巨的任务——决定如何最好地构建数据湖、选择哪种文件格式、是拥有多个数据湖还是只有一个数据湖、如何保护和管理数据湖。并非所有这些都需要在第一天回答&#xff0c;有些可能通过反复试验来确定。构建数据湖没有明确的指南&am…

【C++】一文带你吃透C++多态

&#x1f34e; 博客主页&#xff1a;&#x1f319;披星戴月的贾维斯 &#x1f34e; 欢迎关注&#xff1a;&#x1f44d;点赞&#x1f343;收藏&#x1f525;留言 &#x1f347;系列专栏&#xff1a;&#x1f319; C/C专栏 &#x1f319;那些看似波澜不惊的日复一日&#xff0c;…

【链表part02】| 24.两两交换链表中的节点、19.删除链表的倒数第N个节点、02.07.链表相交、142.环形链表

目录 ✿LeetCode24.两两交换链表中的节点❀ ✿LeetCode19.删除链表的倒数第N个节点❀ ✿LeetCode面试题 02.07. 链表相交❀ ✿LeetCode142.环形链表||❀ ✿LeetCode24.两两交换链表中的节点❀ 链接&#xff1a;24.两两交换链表中的节点 给你一个链表&#xff0c;两两交换其…

轻骑逐单于,大雪满弓刀:华为分布式存储的一骑绝尘

唐代诗人卢纶&#xff0c;有一首脍炙人口的《和张仆射塞下曲》&#xff0c;“月黑雁飞高&#xff0c;单于夜遁逃。欲将轻骑逐&#xff0c;大雪满弓刀。”诗中的慷慨激昂&#xff0c;热血炙烈&#xff0c;千年来让无数国人心魂激荡。 时代变迁&#xff0c;岁月迁移&#xff0c;今…

LeetCode面向运气之Javascript—第20题-有效的括号-95.97%

LeetCode第20题-有效的括号 题目要求 给定一个只包括 ‘(’&#xff0c;‘)’&#xff0c;‘{’&#xff0c;‘}’&#xff0c;‘[’&#xff0c;‘]’ 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。左括号…

卑微小测试的一天----自动生成正交法测试用例

前言 工作过程中&#xff0c;我们接触到需求后第一要务是 熟悉需求并且输出测试用例&#xff0c;针对接口测试的入参测试&#xff0c;需要校验大量入参的组合场景&#xff0c;这时我们通常采用正交法来设计测试用例&#xff0c;在减少测试用例的数量时&#xff0c;同时保障测试…

Java 命名规范

包命名规范 包(Package) 的作用是将功能相似或相关的类或者接口进行分组管理&#xff0c;便于类的定位和查找&#xff0c;同时也可以使用包来避免类名的冲突和访问控制&#xff0c;使代码更容易维护。通常&#xff0c;包名使用小写英文字母进行命名&#xff0c;并使用 “.” 进…

LeetCode——半有序排列

一、题目 2717. 半有序排列 - 力扣&#xff08;Leetcode&#xff09; 给你一个下标从 0 开始、长度为 n 的整数排列 nums 。 如果排列的第一个数字等于 1 且最后一个数字等于 n &#xff0c;则称其为 半有序排列 。你可以执行多次下述操作&#xff0c;直到将 nums 变成一个 …

LeetCode_前缀树_困难_212.单词搜索 II

目录 1.题目2.思路3.代码实现&#xff08;Java&#xff09; 1.题目 给定一个 m x n 二维字符网格 board 和一个单词&#xff08;字符串&#xff09;列表 words&#xff0c; 返回所有二维网格上的单词 。单词必须按照字母顺序&#xff0c;通过相邻的单元格内的字母构成&#xf…

网络安全学术顶会——SP 2023 议题清单、摘要与总结(中)

注&#xff1a;本文由ChatGPT与Claude联合生成 51、Effective ReDoS Detection by Principled Vulnerability Modeling and Exploit Generation 正则表达式拒绝服务攻击&#xff08;ReDoS&#xff09;是一种算法复杂度攻击。对于易受攻击的正则表达式&#xff0c;攻击者可以精心…

kotlin学习(一)基本概念、数据对象类型、控制流程、空值检验、类与接口

文章目录 认识Kotlin跨平台特性语言类型java的语言类型kotlin的运行原理 hello world 基本概念程序入口数据与对象类型 和 显式数字转换浮点类型位运算AnyUnitNothing 声明变量只读变量 val与可变变量var查看Kotlin字节码 fun&#xff08;方法 / 函数&#xff09;函数参数默认值…