Java实现Modbus Tcp协议读写模拟工具数据

news2024/12/26 21:17:30

标题

    • 前言
    • 一、读写模拟工具中数据
      • (1) 定义Controller层
      • (2) 定义Service层实现
    • 二、调试
      • (1) 读数据
      • (2) 向寄存器写单个数据
      • (3) 向寄存器写多个数据

前言

参考文章:https://www.cnblogs.com/ioufev/p/10831289.html

该文中谈及常见的几种读取设备数据实现,说到modbus4j的通讯实现方式是同步的,实际应用中可能会读取大量的数据,需要异步进行,可以用modbus-master-tcp

本文也是基于modbus-master-tcp依赖库进行开发,它底层是基于Netty写的,所以具备高性能、支持异步

SpringBoot项目配置的核心依赖

<!--Modbus Master -->
<dependency>
    <groupId>com.digitalpetri.modbus</groupId>
    <artifactId>modbus-master-tcp</artifactId>
    <version>1.2.0</version>
</dependency>

<!--Modbus Slave -->
<dependency>
    <groupId>com.digitalpetri.modbus</groupId>
    <artifactId>modbus-slave-tcp</artifactId>
    <version>1.2.0</version>
</dependency>

设备模拟工具选择Modbus Slave,网上很多下载资源

一、读写模拟工具中数据

在这里插入图片描述
一开始我也把Server和Client搞混了,大家注意下面重点知识

重点知识

Modbus一主多从讲的是一次只有一个主机(Master)连接到网络,只有主设备(Master)可以启动通信并向从设备(Slave)发送请求,从设备不能主动发送;从设备(Slave)只能向主设备(Master)发送回复,且从设备就不能自己主动发送。

一个Master(物理网平台),多个Slave(设备);平台是Client,设备是Server

实现如下

(1) 定义Controller层

@RestController
@RequestMapping("/modbus")
public class ModbusController {

    @Autowired
    private ModbusTcpService modbusTcpService;

    // 连接slave设备
    @GetMapping(value = "/connect_slave")
    public ResponseMessage connectSlave(){
        return modbusTcpService.connectSlave();
    }

    // 读取保持寄存器
    @PostMapping(value = "/readHoldingRegisters")
    public ResponseMessage readHoldingRegisters(@RequestBody SlaveDto slaveDto) throws ExecutionException, InterruptedException {
        return modbusTcpService.readHoldingRegisters(slaveDto);
    }
    
	// 写单个寄存器
    @PostMapping(value = "/writeSingleRegister")
    public ResponseMessage writeSingleRegister(@RequestBody WriteSlaveDto wsDto) {
        return modbusTcpService.writeSingleRegister(wsDto);
    }

    // 写多个寄存器
    @PostMapping(value = "/writeMultipleRegisters")
    public ResponseMessage writeMultipleRegisters(@RequestBody WriteSlaveDto wsDto){
        return modbusTcpService.writeMultipleRegisters(wsDto);
    }

}

其他相关类

SlaveDto.java

@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
public class SlaveDto {

    private Integer slaveId;

    private Integer address;

    private Integer quantity;
}

WriteSlaveDto.java

@Data
@AllArgsConstructor
@NoArgsConstructor
public class WriteSlaveDto extends SlaveDto {

    // 写单个数值
    private Integer value;

    // 写多个数值
    private int[] values;
}

ResponseMessage.java就是常见的返回msg、code和data的类,随便找一个符合就行

(2) 定义Service层实现

@Service
@Slf4j
public class ModbusTcpService{

	@Autowired
    private ModbusMasterUtil modbusMasterUtil;

	public ResponseMessage connectSlave() {
        try {
            modbusMasterUtil.createModbusConnector(ModbusClientConstants.IP, ModbusClientConstants.TCP_PORT);
            return ResponseMessage.ok();
        }catch (Exception e){
            log.error("connect slave fail, {}", e.getMessage());
            return ResponseMessage.error(e.getMessage());
        }
    }

    private ModbusTcpMaster checkConnectSlave() {
        return modbusMasterUtil.getModbusTcpMaster();
    }

    public ResponseMessage readHoldingRegisters(SlaveDto slaveDto) throws ExecutionException, InterruptedException {
        if (checkConnectSlave() == null) return ResponseMessage.error("not connect slave");

        CompletableFuture<int[]> registerFuture = modbusMasterUtil.readHoldingRegisters(slaveDto.getSlaveId(), slaveDto.getAddress(), slaveDto.getQuantity());
        int[] registerValues = registerFuture.get();
        if (registerFuture == null) return ResponseMessage.error("Read exception, please check json parameters");
        log.info("readHoldingRegisters info={}", Arrays.toString(registerValues));
        return ResponseMessage.ok(registerValues);
    }

    public ResponseMessage writeSingleRegister(WriteSlaveDto wsDto) {
        if (checkConnectSlave() == null) return ResponseMessage.error("not connect slave");

        modbusMasterUtil.writeSingleRegister(wsDto.getSlaveId(), wsDto.getAddress(), wsDto.getValue());
        return ResponseMessage.ok();
    }

    public ResponseMessage writeMultipleRegisters(WriteSlaveDto wsDto) {
        if (checkConnectSlave() == null) return ResponseMessage.error("not connect slave");

        if(wsDto.getValues().length != wsDto.getQuantity()) return ResponseMessage.error("quantity error");

        modbusMasterUtil.writeMultipleRegisters(wsDto.getSlaveId(), wsDto.getAddress(), wsDto.getQuantity(), wsDto.getValues());
        return ResponseMessage.ok();
    }
}

IP和Port就是一个常量类,写着Modbus默认的127.0.0.1和502

Modbus Tcp的工具类为ModbusMasterUtil,这来自于网上的,还挺好用

@Component
@Slf4j
public class ModbusMasterUtil {

    private ModbusTcpMaster modbusMaster = null;

    public ModbusTcpMaster getModbusTcpMaster() {
        return modbusMaster;
    }
 
    /**
     * 将两个int数拼接成为一个浮点数
     *
     * @param highValue 高16位数值
     * @param lowValue  低16位数值
     * @return 返回拼接好的浮点数
     * @author huangji
     */
    public static float concatenateFloat(int highValue, int lowValue) {
        int combinedValue = ((highValue << 16) | (lowValue & 0xFFFF));
        return Float.intBitsToFloat(combinedValue);
    }
 
    public static int[] floatToIntArray(float floatValue) {
        int combinedIntValue = Float.floatToIntBits(floatValue);
        int[] resultArray = new int[2];
        resultArray[0] = (combinedIntValue >> 16) & 0xFFFF;
        resultArray[1] = combinedIntValue & 0xFFFF;
        return resultArray;
    }
 
    /**
     * 将传入的boolean[]类型数组按位转换成byte[]类型数组
     *
     * @param booleans 传入的boolean数组
     * @return 返回转化后的 byte[]
     * @author huangji
     */
    public static byte[] booleanToByte(boolean[] booleans) {
        BitSet bitSet = new BitSet(booleans.length);
        for (int i = 0; i < booleans.length; i++) {
            bitSet.set(i, booleans[i]);
        }
        return bitSet.toByteArray();
    }
 
    /**
     * 将传入的int[]类型数组转换成为byte[]类型数组
     *
     * @param values 传入的int[]数组
     * @return 返回 byte[]类型的数组
     * @author huangji
     */
    public static byte[] intToByte(int[] values) {
        byte[] bytes = new byte[values.length * 2];
        for (int i = 0; i < bytes.length; i += 2) {
            bytes[i] = (byte) (values[i / 2] >> 8 & 0xFF);
            bytes[i + 1] = (byte) (values[i / 2] & 0xFF);
        }
        return bytes;
    }
 
    /**
     * 根据传入的ip地址,创建modbus连接器
     *
     * @param ipAddr ip地址
     * @return 创建连接器,并进行连接,之后返回此连接器
     * @author huangji
     */
    public CompletableFuture<ModbusTcpMaster> createModbusConnector(String ipAddr) {
        return createModbusConnector(ipAddr, ModbusClientConstants.TCP_PORT);
    }
 
    /**
     * 根据传入的ip地址,创建modbus连接器
     *
     * @param ipAddr ip地址
     * @param port   端口号
     * @return 创建连接器,并进行连接,之后返回此连接器
     * @author huangji
     */
    public CompletableFuture<ModbusTcpMaster> createModbusConnector(String ipAddr, int port) {
        return createModbusConnector(new ModbusNetworkAddress(ipAddr, port));
    }
 
    /**
     * 根据传入的ModbusNetworkAddress\引用,创建modbus连接器
     *
     * @param modbusNetworkAddress ModbusNetworkAddress类型的实体对象引用
     * @return 创建连接器,并进行连接,之后返回此连接器
     * @author huangji
     */
    public CompletableFuture<ModbusTcpMaster> createModbusConnector(ModbusNetworkAddress modbusNetworkAddress) {
        String ipAddr = modbusNetworkAddress.getIpAddr();
        int port = modbusNetworkAddress.getPort();
        if (modbusMaster == null) {
            ModbusTcpMasterConfig masterConfig = new ModbusTcpMasterConfig.Builder(ipAddr).setPort(port).setTimeout(Duration.parse(ModbusClientConstants.TIMEOUT_DURATION)).setPersistent(true).setLazy(false).build();
            modbusMaster = new ModbusTcpMaster(masterConfig);
        }
        return modbusMaster.connect();
    }
 
    public void setBooleanArray(short unsignedShortValue, int[] array, int index, int size) {
        for (int i = index; i < index + size; i++) {
            array[i] = (unsignedShortValue & (0x01 << (i - index))) != 0 ? 1 : 0;
        }
    }
 
    /**
     * 异步方法,读取modbus设备的线圈值,对应功能号01
     *
     * @param slaveId  设备id
     * @param address  要读取的寄存器地址
     * @param quantity 要读取的寄存器数量
     * @return 返回 CompletableFuture<int[]>
     * @author huangji
     */
    public CompletableFuture<int[]> readCoils(int slaveId, int address, int quantity) {
        CompletableFuture<ReadCoilsResponse> futureResponse = modbusMaster.sendRequest(new ReadCoilsRequest(address, quantity),
                slaveId);
        return futureResponse.handle((response, ex) -> {
            if (ex != null) {
                ReferenceCountUtil.release(response);
                return null;
            } else {
                ByteBuf byteBuf = response.getCoilStatus();
                int[] values = new int[quantity];
                int minimum = Math.min(quantity, byteBuf.capacity() * 8);
                for (int i = 0; i < minimum; i += 8) {
                    setBooleanArray(byteBuf.readUnsignedByte(), values, i, Math.min(minimum - i, 8));
                }
                ReferenceCountUtil.release(response);
                return values;
            }
        });
    }
 
    /**
     * 异步方法,读取modbus设备的离散输入值,对应功能号02
     *
     * @param slaveId  设备id
     * @param address  要读取的寄存器地址
     * @param quantity 要读取的寄存器数量
     * @return 返回 CompletableFuture<int[]>
     * @author huangji
     */
    public CompletableFuture<int[]> readDiscreteInputs(int slaveId, int address, int quantity) {
        CompletableFuture<ReadDiscreteInputsResponse> futureResponse = modbusMaster.sendRequest(new ReadDiscreteInputsRequest(address, quantity),
                slaveId);
        return futureResponse.handle((response, ex) -> {
            if (ex != null) {
                ReferenceCountUtil.release(response);
                return null;
            } else {
                ByteBuf byteBuf = response.getInputStatus();
                int[] values = new int[quantity];
                int minimum = Math.min(quantity, byteBuf.capacity() * 8);
                for (int i = 0; i < minimum; i += 8) {
                    setBooleanArray(byteBuf.readUnsignedByte(), values, i, Math.min(minimum - i, 8));
                }
                ReferenceCountUtil.release(response);
                return values;
            }
        });
    }

    /**
     * 异步方法,读取modbus设备的保持寄存器值,对应功能号03
     *
     * @param slaveId  设备id
     * @param address  要读取的寄存器地址
     * @param quantity 要读取的寄存器数量
     * @return 返回 CompletableFuture<int[]>
     * @author huangji
     */
    public CompletableFuture<int[]> readHoldingRegisters(int slaveId, int address, int quantity) {
        CompletableFuture<ReadHoldingRegistersResponse> futureResponse = modbusMaster.sendRequest(new ReadHoldingRegistersRequest(address, quantity),
                slaveId);
        return futureResponse.handle((response, ex) -> {
            if (ex != null) {
                ReferenceCountUtil.release(response);
                return null;
            } else {
                ByteBuf byteBuf = response.getRegisters();
                int[] values = new int[quantity];
                for (int i = 0; i < byteBuf.capacity() / 2; i++) {
                    values[i] = byteBuf.readUnsignedShort();
                }
                ReferenceCountUtil.release(response);
                return values;
            }
        });
    }

    /**
     * 异步方法,读取modbus设备的输入寄存器值,对应功能号04
     *
     * @param slaveId  设备id
     * @param address  要读取的寄存器地址
     * @param quantity 要读取的寄存器数量
     * @return 返回 CompletableFuture<int[]>
     * @author huangji
     */
    public CompletableFuture<int[]> readInputRegisters(int slaveId, int address, int quantity) {
        CompletableFuture<ReadInputRegistersResponse> futureResponse = modbusMaster.sendRequest(new ReadInputRegistersRequest(address, quantity),
                slaveId);
        return futureResponse.handle((response, ex) -> {
            if (ex != null) {
                ReferenceCountUtil.release(response);
                return null;
            } else {
                ByteBuf byteBuf = response.getRegisters();
                int[] values = new int[quantity];
                for (int i = 0; i < byteBuf.capacity() / 2; i++) {
                    values[i] = byteBuf.readUnsignedShort();
                }
                ReferenceCountUtil.release(response);
                return values;
            }
        });
    }
 
    /**
     * 异步方法,写入单个线圈的数值,对应功能号05
     *
     * @param slaveId 设备id
     * @param address 要读取的寄存器地址
     * @param value   要写入的boolean值
     * @return 返回 CompletableFuture<Boolean>
     * @author huangji
     */
    public CompletableFuture<Boolean> writeSingleCoil(int slaveId, int address, boolean value) {
        CompletableFuture<WriteSingleCoilResponse> futureResponse = modbusMaster.sendRequest(new WriteSingleCoilRequest(address, value),
                slaveId);
        return futureResponse.handle((response, ex) -> {
            if (ex != null) {
                ReferenceCountUtil.release(response);
                return false;
            } else {
                boolean responseValue = response.getValue() != 0;
                ReferenceCountUtil.release(response);
                return responseValue == value;
            }
        });
    }
 
    /**
     * 异步方法,写入单个寄存器的数值,对应功能号06
     *
     * @param slaveId 设备id
     * @param address 要读取的寄存器地址
     * @param value   要写入的值
     * @return 返回 CompletableFuture<Boolean>
     * @author huangji
     */
    public CompletableFuture<Boolean> writeSingleRegister(int slaveId, int address, int value) {
        CompletableFuture<WriteSingleRegisterResponse> futureResponse = modbusMaster.sendRequest(new WriteSingleRegisterRequest(address, value),
                slaveId);
        return futureResponse.handle((response, ex) -> {
            if (ex != null) {
                ReferenceCountUtil.release(response);
                return false;
            } else {
                int responseValue = response.getValue();
                ReferenceCountUtil.release(response);
                return responseValue == value;
            }
        });
    }
 
    /**
     * 异步方法,写入多个线圈的数值,对应功能号15
     *
     * @param slaveId  设备id
     * @param address  要写入的寄存器地址
     * @param quantity 要写入的寄存器个数
     * @param values   要写入的boolean[]
     * @return 返回 CompletableFuture<Boolean>
     * @author huangji
     */
    public CompletableFuture<Boolean> writeMultipleCoils(int slaveId, int address, int quantity, boolean[] values) {
        byte[] bytes = booleanToByte(values);
        CompletableFuture<WriteMultipleCoilsResponse> futureResponse = modbusMaster.sendRequest(new WriteMultipleCoilsRequest(address, quantity, bytes),
                slaveId);
        return futureResponse.handle((response, ex) -> {
            if (ex != null) {
                ReferenceCountUtil.release(response);
                return false;
            } else {
                int responseQuantity = response.getQuantity();
                ReferenceCountUtil.release(response);
                return values.length == responseQuantity;
            }
        });
    }
 
    /**
     * 异步方法,写入多个寄存器的数值,对应功能号16
     *
     * @param slaveId  设备id
     * @param address  要写入的寄存器地址
     * @param quantity 要写入的寄存器个数
     * @param values   要写入的int[]
     * @return 返回 CompletableFuture<Boolean>
     * @author huangji
     */
    public CompletableFuture<Boolean> writeMultipleRegisters(int slaveId, int address, int quantity, int[] values) {
        byte[] bytes = intToByte(values);
        CompletableFuture<WriteMultipleRegistersResponse> futureResponse = modbusMaster.sendRequest(new WriteMultipleRegistersRequest(address, quantity, bytes),
                slaveId);
        return futureResponse.handle((response, ex) -> {
            if (ex != null) {
                ReferenceCountUtil.release(response);
                return false;
            } else {
                int responseQuantity = response.getQuantity();
                ReferenceCountUtil.release(response);
                return values.length == responseQuantity;
            }
        });
    }
 
    /**
     * 关闭连接器并释放相关资源
     *
     * @author huangji
     */
    public void disposeModbusConnector() {
        if (modbusMaster != null) {
            modbusMaster.disconnect();
        }
        Modbus.releaseSharedResources();
    }
 
}

二、调试

首先要在Modbus Slave工具点击Connect进行连接,随便输入一些数字,然后发送请求;

注:可以先用connect_slave接口发送请求建立平台与设备的连接

(1) 读数据

在这里插入图片描述

(2) 向寄存器写单个数据

在这里插入图片描述

(3) 向寄存器写多个数据

在这里插入图片描述

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

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

相关文章

无硬盘的版本 1099,14寸笔记本,而且无硬盘的,特别有有意思,可以自己购买个硬盘,安装linux系统或者windows。

1&#xff0c;千元笔记本&#xff0c;金属外壳 有人进行评测了&#xff1a; https://www.bilibili.com/video/BV1Td4y1K7Cp 1499元的全新笔记本&#xff0c;有什么猫腻&#xff1f; 看了下价格&#xff0c;现在还优惠400&#xff0c;变成了1099。 https://item.jd.com/100851…

Django — 请求和响应

目录 一、请求1、概念2、请求参数方式分类3、案例3.1、URL 路径参数3.2、查询字符串参数3.3、form 表单传参3.4、Json 格式参数3.5、上传文件 二、响应1、HttpResponse2、JsonResponse 三、GET 和 POST 区别1、相同点2、不同点 一、请求 1、概念 请求&#xff08;Request&…

DDR4 眼图测试方法

DDR的全拼是Double Data Rate SDRAM双倍数据速率同步动态随机存取内存。主要就是用在电脑的内存。他的特点就是走线数量多&#xff0c;速度快&#xff0c;操作复杂&#xff0c;给测试和分析带来了很大的挑战。目前DDR技术已经发展到了DDR5&#xff0c;性能更高&#xff0c;功耗…

【算法练习Day4】 两两交换链表节点删除链表倒数第 N 个结点环形链表 II

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 两两交换链表中的节点一…

毫米波雷达 TI IWR1443 在 ROS 中进行 octomap 建图

个人实验记录 /mmwave_ti_ros/ros_driver/src/ti_mmwave_rospkg/launch/1443_multi_3d_0.launch <launch><!-- Input arguments --><arg name"device" value"1443" doc"TI mmWave sensor device type [1443, 1642]"/><arg…

一例“msvc编译器O2优化导致的崩溃”的分析

1. 初步分析 某进程崩溃必现。 打开崩溃dmp&#xff0c;结合c源代码&#xff0c;崩溃大致发生在某dll代码里的这句&#xff1a;SAFE_DELETE(pContentData); En_HP_HandleResult CTcpOperation::OnClintReceive(HP_Client pSender, HP_CONNID dwConnID, const BYTE * pdata, i…

组队竞赛(int溢出问题)

目录 一、题目 二、代码 &#xff08;一&#xff09;没有注意int溢出 &#xff08;二&#xff09;正确代码 1. long long sum0 2. #define int long long 3. 使用现成的sort函数 一、题目 二、代码 &#xff08;一&#xff09;没有注意int溢出 #include <iostream&g…

机器学习的主要内容

分类任务 回归任务 有一些算法只能解决回归问题有一些算法只能解决分类问题有一些算法的思路既能解决回归问题&#xff0c;又能解决分类问题 一些情况下&#xff0c; 回归任务可以转化为分类任务&#xff0c; 比如我们预测学生的成绩&#xff0c;然后根据学生的成绩划分为A类、…

js制作柱状图的x轴时间, 分别展示 月/周/日 的数据

背景 有个需求是要做一个柱状图, x 轴是时间, y 轴是数量. 其中 x 轴的时间有三种查看方式: 月份/周/日, 也就是分别查看从当前日期开始倒推的最近每月/每周/每日的数量. 本篇文章主要是用来制作三种不同的 x 轴 从当前月开始倒推月份 注意 getMonth() 函数可以获取当前月份…

【【萌新的FPGA学习之实战流水灯】】

萌新的FPGA学习之实战流水灯 实验任务 本节的实验任务是使用领航者底板上的两个 PL LED 灯顺序点亮并熄灭&#xff0c;循环往复产生流水灯的效 果&#xff0c;流水间隔时间为 0.5s。 1MHz&#xff1d;1000000Hz 10的6次方 1ns&#xff1d;10的-9次方秒 开发板晶振50Mhz 计算得…

如何看待Unity新的收费模式?

文章目录 背景Unity的论点开发者的担忧如何看待Unity新的收费模式&#xff1f;1. 理解Unity的立场2. 考虑小型开发者3. 探索替代方案4. 对市场变化保持敏感5. 提高游戏质量 结论 &#x1f389; 如何看待Unity新的收费模式&#xff1f; ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1…

R语言柱状图直方图 histogram

柱状图简介 柱状图也叫直方图&#xff0c;是展示连续性数值的分布状况。在x轴上将连续型数值分为一定数量的组&#xff0c;y轴显示对应值的频数。 R基本的柱状图 hist 我们用R自带的Orange数据来画图。 > head(Orange)Tree age circumference(圆周长) 1 1 118 …

Docker搭建DNS服务器--nouse

前言 DNS服务器是(Domain Name System或者Domain Name Service)域名系统或者域名服务,域名系统为Internet上的主机分配域名地址和IP地址。 安装 2.1 实验环境 IP 系统版本 角色 192.168.40.121 Ubuntu 22.10 DNS服务器 192.168.40.122 Ubuntu 22.10 测试机器 2.2 …

数据库选型参考

嵌入式数据库 SQLite、Berkeley DB、Derby、H2、HSQL DB SQLite&#xff1a; SQLite是一种非常流行的文件型数据库&#xff0c;它是一款轻量级、高性能、开源的嵌入式数据库引擎。SQLite采用C语言编写&#xff0c;可以在各种操作系统上运行&#xff0c;并且支持大多数标准SQL语…

csa从初阶到大牛(训练题1)

使用普通账户新建如下结构的2个目录&#xff1a; ~/t1/t2/t3/t4&#xff0c;~/m1/m2/m3/m4,并显示t1目录的详细信息&#xff0c;将/etc/passwd文件拷贝到~/t1/t2/t3目录下面&#xff0c;将~/t1/下面的内容拷贝到~/m1/m2/m/3/m4目录下面,最后删除~/t1/t2/t3下面的目录 # 创建目…

前端JavaScript入门到精通,javascript核心进阶ES6语法、API、js高级等基础知识和实战 —— JS基础(四)

开始吧&#xff0c;做时间的主人&#xff01; 把时间分给睡眠&#xff0c;分给书籍&#xff0c;分给运动&#xff0c; 分给花鸟树木和山川湖海&#xff0c; 分给你对这个世界的热爱&#xff0c; 而不是将自己浪费在无聊的人和事上。 思维导图 函数 为什么需要函数 <!DO…

pytest框架运行时的参数,以及多线程分布式运行用例、运行指定模块用例

一、运行时的参数 在上一篇博客中写了pytest最为核心的运行时前后置如何设置&#xff0c;细心的朋友可能也会发现其实我们当时就加过运行时的参数-vs。 pytest.main([‘-s’])&#xff1a;能打印出调试信息&#xff0c;print()或者日志都可以直接打印在控制台上。 pytest.ma…

栈和队列1——栈的实现及其oj(括号匹配问题)

一&#xff0c;栈的概念 栈是一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 压栈&#xf…

【100天精通Python】Day68:Python可视化_Matplotlib 绘制热力图,示例+代码

目录 1 值热力图&#xff08;Value Heatmap&#xff09;: 2 密度热力图&#xff08;Density Heatmap&#xff09; 3 时间热力图&#xff08;Time Heatmap&#xff09;: 4 空间热力图&#xff08;Spatial Heatmap&#xff09; 5 渐变热力图&#xff08;Gradient Heatmap&am…

C语言实现获取文件大小(字节数)

首先使用如下命令在当前文件夹&#xff0c;创建一个大小为1234578字节的空白文件&#xff1a; fsutil file createnew ./test.bin 12345678关于fsutil命令的介绍&#xff1a;Windows快速创建任意大小的空白文件 使用十六进制编辑器打开&#xff0c;可以看到内容全是0&#xf…