NIO-Channel详解

NIO-Channel详解

1.Channel概述

Channel即通道,表示打开IO设备的连接,⽐如打开到⽂件、Socket套接字的连接。在使⽤NIO时,必须要获取⽤于连接IO设备的通道以及⽤于容纳数据的缓冲区。通过操作缓冲区,实现对数据的处理。也就是说数据是保存在buffer缓冲区中的,需要通过Channel来操作缓冲区中的数据。

Channel相⽐IO流中的Stream更加⾼效,可以异步双向传输。

Channel的主要实现类有以下⼏个:

  • FileChannel:读写⽂件的通道

  • SocketChannel:读写TCP⽹络数据的通道

  • ServerSocketChannel:像web服务器⼀样,监听新进来的TCP连接,为连接创建SocketChannel

  • DatagramChannel:读写UDP⽹络数据的通道

2.FileChannel详解

FileChannel介绍

⽤于读取、写⼊、映射和操作⽂件的通道。⽂件通道是连接到⽂件的可搜索字节通道。它在其⽂件中有⼀个当前位置,可以查询和修改。⽂件本身包含可变⻓度的字节序列,可以读取和写⼊,并且可以查询其当前⼤⼩。当写⼊的字节超过其当前⼤⼩时,⽂件的⼤⼩增加;⽂件被截断时,其⼤⼩会减⼩。⽂件还可能具有⼀些相关联的元数据,如访问权限、内容类型和上次修改时间;此类不定义元数据访问的⽅法。

除了熟悉的字节通道读、写和关闭操作外,此类还定义了以下⽂件特定操作:

  • 字节可以以不影响通道当前位置的⽅式在⽂件中的绝对位置读取或写⼊。

  • ⽂件的区域可以直接映射到存储器中;对于⼤型⽂件,这⽐调⽤通常的读或写⽅法更有效。

  • 对⽂件进⾏的更新可能会被强制输出到底层存储设备,以确保在系统崩溃时数据不会丢失。

  • 字节可以从⼀个⽂件传输到另⼀个通道,反之亦然,许多操作系统都可以将其优化为直接从⽂件系统缓存进⾏⾮常快速的传输。

  • ⽂件的⼀个区域可以被锁定以防⽌其他程序访问。

多个并发线程使⽤⽂件通道是安全的。根据通道接⼝的指定,可以随时调⽤close⽅法。在任何给定时间,只有⼀个涉及通道位置或可以改变其⽂件⼤⼩的操作正在进⾏;在第⼀个操作仍在进⾏时尝试发起第⼆个这样的操作将被阻⽌,直到第⼀个操作完成。其他⾏动,特别是采取明确⽴场的⾏动,可以同时进⾏;它们是否真的这样做取决于底层实现,因此没有具体说明。

FileChannel实例

  • FileChannel读文件

    package com.my.io.channel.file;
    ​
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    ​
    /**
     * @author zhupanlin
     * @version 1.0
     * @description: FileChannel 读文件
     * @date 2024/1/25 10:09
     */
    public class Demo1 {
    ​
        public static void main(String[] args) throws IOException {
            // 随机访问流
            RandomAccessFile file = new RandomAccessFile("1.txt", "rw");
            // 得到FileChannel
            FileChannel fileChannel = file.getChannel();
            // 创建Buffer
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            // 通过fileChannel读取数据到buffer中
            int len = 0;
            while ((len = fileChannel.read(buffer)) != -1){
                // 在当前的Java程序中把buffer中的数据显示出来
                // 把写的模式转换成读的模式
                buffer.flip();
                // 读buffer中的数据
                while (buffer.hasRemaining()){
                    // 获得buffer中的数据
                    byte b = buffer.get();
                    System.out.print(((char) b));
                }
                // buffer清除
                buffer.clear();
            }
            file.close();
        }
        
    }
  • FileChannel写数据

    package com.my.io.channel.file;
    ​
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    ​
    /**
     * @author zhupanlin
     * @version 1.0
     * @description: FileChannel写数据
     * @date 2024/1/25 10:24
     */
    public class Demo2 {
    ​
        public static void main(String[] args) throws IOException {
            // 创建随机访问流
            RandomAccessFile file = new RandomAccessFile("2.txt", "rw");
            // 获得FileChannel
            FileChannel fileChannel = file.getChannel();
            // 创建buffer对象
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            // 数据
            String data = "hello file channel";
            // 存入buffer
            buffer.put(data.getBytes());
            // 翻转buffer,position->0,limit->最大的位置
            buffer.flip();
            // fileChannel 写数据到文件
            fileChannel.write(buffer);
            // 关闭
            fileChannel.close();
            file.close();
        }
        
    }
  • 通道之间传输数据一

    package com.my.io.channel.file;
    ​
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.nio.channels.FileChannel;
    ​
    /**
     * @author zhupanlin
     * @version 1.0
     * @description: 通道间的数据传输
     * @date 2024/1/25 10:34
     */
    public class Demo3 {
    ​
        public static void main(String[] args) throws IOException {
            // 创建两个channel
            RandomAccessFile srcFile = new RandomAccessFile("1.txt", "rw");
            FileChannel srcfileChannel = srcFile.getChannel();
            RandomAccessFile destFile = new RandomAccessFile("3.txt", "rw");
            FileChannel destFileChannel = destFile.getChannel();
            // src -> dest
            destFileChannel.transferFrom(srcfileChannel, 0,srcfileChannel.size());
            // 关闭
            srcfileChannel.close();
            destFileChannel.close();
            System.out.println("传输完成");
    ​
        }
        
    }
  • 通道之间传输数据二

    package com.my.io.channel.file;
    ​
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.nio.channels.FileChannel;
    import java.util.Random;
    ​
    /**
     * @author zhupanlin
     * @version 1.0
     * @description: 通道之间数据传输
     * @date 2024/1/25 10:39
     */
    public class Demo4 {
    ​
        public static void main(String[] args) throws IOException {
            // 获得两个文件的channel
            RandomAccessFile srcFile = new RandomAccessFile("1.txt", "rw");
            FileChannel srcFileChannel = srcFile.getChannel();
            RandomAccessFile destFile = new RandomAccessFile("4.txt", "rw");
            FileChannel destFileChannel = destFile.getChannel();
            
            // src -> dest
            srcFileChannel.transferTo(0, srcFileChannel.size(), destFileChannel);
            // 关闭
            srcFileChannel.close();
            destFileChannel.close();
        }
        
    }
    ​

3.Socket通道介绍

⾯向流的连接通道。Socket通道⽤于管理socket和socket之间的通道。Socket通道具有以下特点:

  • 可以实现⾮阻塞,⼀个线程可以同时管理多个Socket连接,提升系统的吞吐量。

  • Socket通道的实现类(DatagramChannel、SocketChannel和ServerSocketChannel)在被实例化时会创建⼀个对等的Socket对象,也可以从Socket对象中通过getChannel()⽅法获得对应的Channel。

4.ServerSocketChannel详解

ServerSocketChannel是⼀个基于通道的Socket监听器,能够实现⾮阻塞模式。

ServerSocketChannel的主要作⽤是⽤来监听端⼝的连接,来创建SocketChannel。也就是说,可以调⽤ServerSocketChannel的accept⽅法,来创建SocketChannel对象。

示例

package com.my.io.channel.socket;
​
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
​
/**
 * @author zhupanlin
 * @version 1.0
 * @description: ServerSocketChannel
 * @date 2024/1/25 11:04
 */
public class ServerSocketChannelDemo {
​
    public static void main(String[] args) throws IOException {
        // 创建出ServerSocketChannel
        ServerSocketChannel ssc = ServerSocketChannel.open();
        // 绑定端口
        ssc.socket().bind(new InetSocketAddress(9090));;
        // 设置成非阻塞的模式
        //ssc.configureBlocking(false);
        // 监听客户端连接
        while (true){
            System.out.println("等待连接...");
            // 当有客户端连接上来,则创建出SocketChannel对象
            SocketChannel socketChannel = ssc.accept();
            if (socketChannel != null){
                System.out.println(socketChannel.socket().getRemoteSocketAddress() + "已连接");
            }else {
                System.out.println("继续等待");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
}

5.SocketChannel详解

SocketChannel介绍

SocketChannel是连接到TCP⽹络套接字的通道,更多代表的是客户端的操作。

SocketChannel具有以下特点:

  • SocketChannel连接的是Socket套接字,也就是说通道的两边是Socket套接字

  • SocketChannel是⽤来处理⽹络IO的通道

  • SocketChannel是可选择的,可以被多路复⽤

  • SocketChannel基于TCP连接传输

SocketChannel使⽤细节

SocketChannel在使⽤上需要注意以下细节:

  • 不能在已经存在的Socket上再创建SocketChannel

  • SocketChannel需要指明关联的服务器地址及端⼝后才能使⽤

  • 未进⾏连接的SocketChannel进⾏IO操作时将抛出NotYetConnectedException异常

  • SocketChannel⽀持阻塞和⾮阻塞两种模式

  • SocketChannel⽀持异步关闭。

  • SocketChannel⽀持设定参数

参数名称Description
SO_SNDBUFSocket发送缓冲区的大小
SO_RCVBUFSocket接收缓冲区的大小
SO_KEEPALIVE保活连接
SO_REUSEADDR复用地址
SO_LINGER有数据传输时延缓关闭Channel
TCP——NODELAY禁用Nagle算法

SocketChannel示例

  • 创建SocketChannel,同时会去连接服务端

    • 方式一

      SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("localhost", 9090));
    • 方式二

      SocketChannel socketChannel = SocketChannel.open();
      socketChannel.connect(new InetSocketAddress("localhost", 9090));

  • 连接状态校验

    • socketChannel.isOpen(): 判断SocketChannel是否为open状态

    • socketChannel.isConnected(): 判断SocketChannel是否已连接

    • socketChannel.isConnectionPending(): 判断SocketChannel是否正在进⾏连接

    • socketChannel.finishConnect(): 完成连接,如果此通道已连接,则此⽅法将不会阻塞,并将⽴即返回true。如果此通道处于⾮阻塞模式,则如果连接过程尚未完成,则此⽅法将返回false。如果此通道处于阻塞模式,则此⽅法将阻塞,直到连接完成或失败,并且将始终返回true或抛出⼀个描述失败的检查异常。

  • 阻塞与非阻塞

    //设置⾮阻塞
    socketChannel.configureBlocking(false);
  • 读写操作

    package com.my.io.channel.socket;
    ​
    ​
    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.net.StandardSocketOptions;
    import java.nio.ByteBuffer;
    import java.nio.channels.SocketChannel;
    ​
    /**
     * @author zhupanlin
     * @version 1.0
     * @description: 使用SocketChannel
     * @date 2024/1/25 11:40
     */
    public class SocketChannelDemo2 {
    ​
        public static void main(String[] args) throws IOException {
            // 获得SocketChannel
            SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("www.baidu.com", 80));
            // 设置成非阻塞的模式
            socketChannel.configureBlocking(false);
            // 设置接收缓冲区的大小
            socketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 1024);
            // 设置发送缓冲区的大小
            socketChannel.setOption(StandardSocketOptions.SO_SNDBUF, 2048);
            System.out.println("socketChannel.getOption(StandardSocketOptions.SO_SNDBUF) = " + socketChannel.getOption(StandardSocketOptions.SO_SNDBUF));
            // 判断socket是否正在连接,如果正在连接,就让他连接成功
            if (socketChannel.isConnectionPending()){
                socketChannel.finishConnect();
            }
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            int len = socketChannel.read(buffer);
            if (len == 0){
                System.out.println("没有读到数据!");
            }else if (len == -1){
                System.out.println("数据读完了");
            }
            else{
                System.out.println("读取到内容:" + new String(buffer.array(), 0, len));
            }
            socketChannel.close();
        }
        
    }

6.DatagramChannel详解

DatagramChannel对象关联着⼀个DatagramSocket对象。

DatagramChannel基于UDP⽆连接协议,每个数据报都是⼀个⾃包含的实体,拥有它⾃⼰的⽬的地址及数据负载。DatagramChannel可以发送单独的数据报给不同的⽬的地,同样也可以接受来⾃于任意地址的数据报。

  • 示例一

    @Test
        public void testSend() throws IOException {
            // 获得DatagramChannel
            DatagramChannel datagramChannel = DatagramChannel.open();
            // 创建地址对象
            InetSocketAddress socketAddress = new InetSocketAddress("localhost", 9001);
            // 创建Buffer对象,Buffer里面需要有数据
            /*ByteBuffer buffer = ByteBuffer.allocate(1024);
            buffer.put("hello datagram".getBytes());
            buffer.flip();*/
            ByteBuffer buffer = ByteBuffer.wrap("hello datagram".getBytes());
            // 发送消息
            datagramChannel.send(buffer, socketAddress);
        }
        
        @Test
        public void testReceive() throws IOException {
            // 获得DatagramChannel
            DatagramChannel datagramChannel = DatagramChannel.open();
            // 创建一个描述端口的地址对象
            InetSocketAddress socketAddress = new InetSocketAddress(9001);
            // 绑定端口到channel上
            datagramChannel.bind(socketAddress);
            // 接收消息并解析
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            while (true){
                // 清空buffer
                buffer.clear();
                // 接收数据并获得当前数据来自于哪里的地址对象
                SocketAddress address = datagramChannel.receive(buffer);
                // 反转buffer
                buffer.flip();
                // 解析
                System.out.println(address.toString() + "发来的消息" + new String(buffer.array(), 0, buffer.limit()));
            }
        }

  • 使用read和write来表示接收和发送

    DatagramChannel并不会建立连接通道,这里的read和write方法是在缓冲区中进行读写,来表达发送和接收的动作。

    @Test
        public void testReadAndWrite() throws IOException {
            // 获得DatagramChannel
            DatagramChannel datagramChannel = DatagramChannel.open();
            // 绑定 端口,接收消息
            datagramChannel.bind(new InetSocketAddress(9002));
            // 连接 表明消息到达的ip和端口
            datagramChannel.connect(new InetSocketAddress("localhost", 9002));
            // write
            ByteBuffer byteBuffer = ByteBuffer.wrap("hello read and write".getBytes());
            datagramChannel.write(byteBuffer);
            // read
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            while (true){
                buffer.clear();
                datagramChannel.read(buffer);
                buffer.flip();
                System.out.println("收到的消息:" + new String(buffer.array(), 0, buffer.limit()));
            }
        }

7.分散和聚集

Java NIO的分散Scatter和聚集Gather允许⽤户通过channel⼀次读取到的数据存⼊到多个buffer中,或者⼀次将多个buffer中的数据写⼊到⼀个Channel中。分散和聚集的应⽤场景可以是将数据的多个部分存放在不同的buffer中来进⾏读写

  • 分散Scatter

在一个channel中读取的数据存入到多个buffer中

package com.my.io.channel.scatterandgather;
​
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
​
/**
 * @author zhupanlin
 * @version 1.0
 * @description: 分散
 * @date 2024/1/25 14:28
 */
public class ScatterDemo {
​
    public static void main(String[] args) throws IOException {
        // 随机访问流
        RandomAccessFile file = new RandomAccessFile("1.txt", "rw");
        // 得到FileChannel
        FileChannel fileChannel = file.getChannel();
        // 创建两个buffer
        ByteBuffer buffer1 = ByteBuffer.allocate(5);
        ByteBuffer buffer2 = ByteBuffer.allocate(1024);
        // channel读文件中的数据写入到buffer中
        ByteBuffer[] byteBuffers = new ByteBuffer[]{buffer1, buffer2};
        long len = 0;
        while ((len = fileChannel.read(byteBuffers)) != -1){
            
        }
        // 打印出两个buffer中的数据
        buffer1.flip();
        buffer2.flip();
        System.out.println("buffer1:" + new String(buffer1.array(), 0, buffer1.limit()));
        System.out.println("buffer2:" + new String(buffer2.array(), 0, buffer2.limit()));
        fileChannel.close();
        
    }
    
}
  • 聚集

一次将多个buffer中的数据写入到一个channel中

package com.my.io.channel.scatterandgather;
​
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
​
/**
 * @author zhupanlin
 * @version 1.0
 * @description: 聚集
 * @date 2024/1/25 14:48
 */
public class GatherDemo {
​
    public static void main(String[] args) throws IOException {
        // 创建随机访问流
        RandomAccessFile file = new RandomAccessFile("6.txt", "rw");
        // 得到fileChannel
        FileChannel fileChannel = file.getChannel();
        // 创建两个buffer对象
        ByteBuffer buffer1 = ByteBuffer.allocate(1024);
        ByteBuffer buffer2 = ByteBuffer.allocate(1024);
        // 存入数据到buffer1
        String data1 = "hello buffer1";
        buffer1.put(data1.getBytes());
        buffer1.flip();
        // 存入数据到buffer2
        String data2 = "hello buffer2";
        buffer2.put(data2.getBytes());
        buffer2.flip();
        // channel写数据
        fileChannel.write(new ByteBuffer[]{buffer1, buffer2});
        // 关闭file流
        fileChannel.close();
    }
    
}
​

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

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

相关文章

从源头到成品:精酿啤酒原料的完整追踪

对于追求品质的Fendi Club啤酒来说,从源头到成品的完整原料追踪是确保其品质的关键。这种追踪不仅涉及原料的采购,还包括其在生产过程中的处理和产品的质量控制。下面,我们将详细探讨Fendi Club啤酒如何实现从源头到成品的完整原料追踪。 首先…

安全用电管理平台方案介绍——Acrelcloud-6000

安全用电管理平台是一个针对电力系统安全管理的平台,旨在提供对电力设备和用电行为进行监控、分析和管理的解决方案。该平台结合了物联网技术、数据分析和远程监控等技术手段,能够实时监测、分析和预警电力系统的安全状况,以便及时采取措施防…

电气火灾监控探测器的种类有哪些?

随着电力行业的快速发展,电气火灾的威胁也越来越突出。为了有效预防和及时发现电气火灾,电气火灾探测器成为了不可或缺的重要设备。本文将详细介绍电气火灾探测器的定义、工作原理、应用场景以及安装和维护方法,旨在帮助大家更好地了解和使用…

爬取第一试卷网高三数学试卷并下载到本地

import requests import re import os filename 试卷\\ if not os.path.exists(filename):os.mkdir(filename) url https://www.shijuan1.com/a/sjsxg3/list_727_1.html headers {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.…

Android消息推送 SSE(Server-Sent Events)方案实践

转载请注明出处:https://blog.csdn.net/kong_gu_you_lan/article/details/135777170 本文出自 容华谢后的博客 0.写在前面 最近公司项目用到了消息推送功能,在技术选型的时候想要找一个轻量级的方案,偶然看到一篇文章讲ChatGPT的对话机制是基…

[蓝桥杯]真题讲解:冶炼金属(暴力+二分)

蓝桥杯真题视频讲解&#xff1a;冶炼金属&#xff08;暴力做法与二分做法&#xff09; 一、视频讲解二、暴力代码三、正解代码 一、视频讲解 视频讲解 二、暴力代码 //暴力代码 #include<bits/stdc.h> #define endl \n #define deb(x) cout << #x << &qu…

【江科大】STM32:DMA转运

DMA 直接存储器存取&#xff08;协助CPU完成数据转运&#xff0c;可以直接访问32位内部存储器&#xff0c;内存SRAM&#xff0c;程序存储器Flash&#xff0c;寄存器等&#xff09; DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输&#xff0c;无须CPU干预&#…

银行数据仓库体系实践(7)--数据模型设计及流程

数据仓库作为全行或全公司的数据中心和总线&#xff0c;汇集了全行各系统以及外部数据&#xff0c;通过良好的系统架构可以保证系统稳定性和处理高效性&#xff0c;那如何保障系统数据的完备性、规范性和统一性呢&#xff1f;这里就需要有良好的数据分区和数据模型&#xff0c;…

STM32实现软件IIC协议操作OLED显示屏(1)

时间记录&#xff1a;2024/1/25 一、IIC协议介绍 &#xff08;1&#xff09;协议介绍 IIC&#xff08;又称I2C&#xff0c;Inter-Integrated Circuit&#xff09;&#xff0c;即集成电路总线&#xff0c;是一种两线式串行总线&#xff0c;由PHILIPS公司开发&#xff0c;用…

初识C语言·自定义类型(2)

目录 1 结构体的声明和定义 2 结构体的自引用 3 结构体成员访问操作符 4 内存对齐 4 结构体传参 5 位段 1 结构体的声明和定义 什么是结构&#xff1f;结构也就是元素的集合&#xff0c;在C语言里面&#xff0c;结构体里面的可以有多个变量&#xff0c;类似于集合中的元素…

LabVIEW准分子激光器控制系统

LabVIEW准分子激光器控制系统是为了实现准分子激光光源在工业、医疗和科研领域的应用集成及其功能的扩展。系统由PC端和激光器端两部分构成&#xff0c;通过光隔离的RS232通讯连接&#xff0c;以实现稳定可靠的控制与通信。 系统主要由微控制单元&#xff08;MCU&#xff09;主…

Python解释器的启动方式

Python解释器的启动方式 Python 解释器是一个运行 Python 代码的程序。它读取并执行写成 Python 语言的指令。由于 Python 是一种解释型语言&#xff0c;所以它的代码不需要编译成机器语言就可以直接运行。这就是为什么我们需要一个解释器来逐行读取 Python 代码&#xff0c;将…

linux centos 查看端口是否打开与打开端口

查看端口是否打开 talnet talnet ip 端口linux查看防火墙开放情况 firewall-cmd --list-all打开端口 其中permanent表示永久生效&#xff0c;public表示作用域&#xff0c;443/tcp表示端口和类型&#xff0c;执行规则的重载 firewall-cmd --zonepublic --add-port443/tcp …

Shell脚本——循环语句(for、while和until循环)

一、命令 1.echo命令 echo -n 表示不换行输出 echo -e 输出转义字符&#xff0c;将转义后的内容输出到屏幕上 常见转义字符&#xff1a; \b 相当于退格键 转义后相当于退格键&#xff08;backspace&#xff09;&#xff0c;但是前提是“\b”存在字符。“\b”表示删除前一个…

按条件自动搜索文件

在计算机的某个文件夹中&#xff0c;假如有一大堆不同格式的文件&#xff0c;如下图&#xff1a; 我们的目的&#xff1a;快速查找出文件名中包含某文字内容的指定格式的文件&#xff0c;看看它们都放在哪里&#xff1f;通过分析&#xff0c;可能在当前文件夹中也可能在某个子…

LabVIEW探测器CAN总线系统

介绍了一个基于FPGA和LabVIEW的CAN总线通信系统&#xff0c;该系统专为与各单机进行系统联调测试而设计。通过设计FPGA的CAN总线功能模块和USB功能模块&#xff0c;以及利用LabVIEW开发的上位机程序&#xff0c;系统成功实现了CAN总线信息的收发、存储、解析及显示功能。测试结…

FinBert模型:金融领域的预训练模型

文章目录 模型及预训练方式模型结构训练语料预训练方式 下游任务实验结果实验一&#xff1a;金融短讯类型分类实验任务数据集实验结果 实验二&#xff1a;金融短讯行业分类实验任务数据集实验结果 实验三&#xff1a;金融情绪分类实验任务数据集实验结果 实验四&#xff1a;金融…

RT-Thread: STM32 SPI使用流程

1.添加驱动 ①点开设置界面 ②勾选看门 SPI 驱动 ③点击保存 ④查看添加的驱动文件 drv_spi.c 2.打开驱动头文件定义 ①打开配置文件 ②打开定义 3.打开需要开启的SPI总线 打开 drivers 目录下的 board.h 用SPI搜索&#xff0c;找到如下文字&#xff0c;打开对应的宏。 /*-…

非官方 Bevy 作弊书07-09

源自 网页 Working with 2D - Unofficial Bevy Cheat Book 个人用 有道 翻译&#xff0c;希望能够帮助像我一样的 英语不好 的 bevy 初学者 非官方 Bevy 作弊书 7 使用 bevy 2D 本章涵盖与使用 Bevy 制作 2D 游戏相关的主题。 2D Camera Setup - Unofficial Bevy Cheat Book 非…

架构篇26:高可用存储架构-集群和分区

文章目录 数据集群数据分区小结上一篇我们讨论了高可用存储架构中常见的双机架构,分别为主备复制、主从复制、双机切换和主主复制,并分析了每类架构的优缺点以及适应场景。 今天我们一起来看看另外两种常见的高可用存储架构:数据集群和数据分区。 数据集群 主备、主从、主…