HarmonyOS开发实战( Beta5.0)蓝牙实现服务端和客户端通讯详解

news2025/1/11 8:13:51

鸿蒙HarmonyOS开发往期必看:

HarmonyOS NEXT应用开发性能实践总结

最新版!“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线!(从零基础入门到精通)


介绍

本示例分为服务端和客户端两个功能模块。
服务端创建蓝牙服务实例,添加心率跳动服务。以心率跳动值作为特征值,通过notifyCharacteristicChanged接口将心率跳动特征值广播发送给连接到本服务端并订阅了该特征值变动通知的蓝牙客户端设备。
客户端以特定服务UUID作为过滤条件扫描服务端,连接到扫描的设备后通过setCharacteristicChangeNotification接口向服务端发送‘通知心率跳动特征值变动’的请求,以便收到服务端该特征值变动的通知消息。

主要有以下几点功能:

  1. 发现具有特定服务的设备。
  2. 连接到设备。
  3. 发现服务。
  4. 发现服务的特征、读取给定特征的值、为特征设置通知等。

相关概念:

  1. BLE扫描:通过BLE扫描接口startBLEScan实现对BLE设备的搜索。
  2. BLE连接:通过BLE的GattClientDevice实现对BLE设备的连接、断连等操作。
  3. 接收数据:通过BLECharacteristicChange接收特征值的改变。

效果图预览

使用说明

  1. 该功能需要两台设备,进入BLE通讯场景页面,选择当前设备是作为BLE服务端还是BLE客户端。
  2. 点击“BLE服务端”,进入服务端页面。点击“开启BLE心率广播”,打开蓝牙服务,向订阅了心率跳动值通知的客户端广播发送实时心率值。
  3. 点击“BLE客户端”,进入客户端页面。点击“搜索设备”,搜索开启了心率跳动服务的BLE服务端,连接搜索到的蓝牙设备。连接成功后,点击设备右边的“已连接”,进入心率波动图页面查看实时心率。

实现思路

服务端
  1. 开启或关闭蓝牙广播服务。源码参考BluetoothAdvertiser.ets及startAdvertiser。

    toggleAdvertiser(): void {
     if (this.startAdvertiserState) {
       //  TODO: 知识点 关闭蓝牙广播服务
       advertiserBluetoothViewModel.stopAdvertiser();
       this.toggleHeartRate(false);
       this.startAdvertiserState = false;
     } else {
       //  TODO: 知识点 开启蓝牙广播服务
       let ret = advertiserBluetoothViewModel.startAdvertiser();
       if (ret) {
         this.localName = advertiserBluetoothViewModel.getLocalName();
         // 模拟心率跳动
         this.toggleHeartRate(true);
         this.startAdvertiserState = true;
       } else {
         Log.showError(TAG, `toggleAdvertiser: ret = ${ret}`);
       }
     }
    }
    
     // TODO: 知识点 创建蓝牙服务实例
     this.mGattServer = ble.createGattServer();
    
     let descriptors: Array<ble.BLEDescriptor> = [];
     const arrayBuffer = ArrayBufferUtils.byteArray2ArrayBuffer([11]);
     const descriptor: ble.BLEDescriptor = {
       serviceUuid: BleConstants.UUID_SERVICE_HEART_RATE, //  特定服务(service)的 UUID
       characteristicUuid: BleConstants.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT, // 特定特征(characteristic)的 UUID
       descriptorUuid: BleConstants.UUID_DESCRIPTOR_HEART_RATE, // 描述符(descriptor)的 UUID
       descriptorValue: arrayBuffer  // 描述符对应的二进制值
     };
     descriptors[0] = descriptor;
    
     let characteristics: Array<ble.BLECharacteristic> = [];
     const arrayBufferC = ArrayBufferUtils.byteArray2ArrayBuffer([1]);
     const characteristic: ble.BLECharacteristic = {
       serviceUuid: BleConstants.UUID_SERVICE_HEART_RATE, // 特定服务(service)的 UUID
       characteristicUuid: BleConstants.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT, // 特定特征(characteristic)的 UUID
       characteristicValue: arrayBufferC, // 特征对应的二进制值
       descriptors: descriptors  // 特定特征的描述符列表
     };
     characteristics[0] = characteristic;
     // 定义心率跳动服务
     const service: ble.GattService = {
       serviceUuid: BleConstants.UUID_SERVICE_HEART_RATE,
       isPrimary: true, // 主服务
       characteristics: characteristics,
       includeServices: []
     };
    
     try {
       // 添加服务
       this.mGattServer.addService(service);
       Log.showInfo(TAG, `startAdvertiser: addService suc`);
     } catch (err) {
       Log.showError(TAG, `startAdvertiser: addService err = ${err}`);
     }
    
     try {
       // 订阅连接服务状态
       this.onConnectStateChange();
    
       // 设置广播发送的参数
       let setting: ble.AdvertiseSetting = {
         interval: DurationConstants.ADVERTISE_INTERVAL, // 广播间隔,最小值设置160个slot表示100ms
         txPower: 1, // 发送功率,最小值设置-127,最大值设置1,默认值设置-7
         connectable: true  // 是否是可连接广播
       };
       // BLE广播包内容
       let advData: ble.AdvertiseData = {
         serviceUuids: [BleConstants.UUID_SERVICE_HEART_RATE], // 要广播的服务 UUID 列表
         manufactureData: [], // 广播的制造商信息列表
         serviceData: [], // 广播的服务数据列表
       };
       // BLE回复扫描请求回复响应
       let advResponse: ble.AdvertiseData = {
         serviceUuids: [BleConstants.UUID_SERVICE_HEART_RATE],
         manufactureData: [],
         serviceData: [],
       };
       // TODO: 知识点 开始广播
       ble.startAdvertising(setting, advData, advResponse);
       Log.showInfo(TAG, `startAdvertiser: startAdvertising success`);
       return true;
     } catch (err) {
       Log.showError(TAG, `startAdvertiser: startAdvertising err = ${err}`);
     }
    
  2. 服务开启状态下,广播通知特征值变动。源码参考BluetoothAdvertiser.ets及notifyCharacteristicChanged。

       this.mIntervalId = setInterval(() => {
         this.heartRate = MathUtils.getRandomInt(MIN_HEART_RATE, MAX_HEART_RATE);
         if (this.deviceId) {
           // TODO: 知识点 通知客户端心率特征值变动
           advertiserBluetoothViewModel.notifyCharacteristicChanged(this.deviceId, this.heartRate);
         } else {
           Log.showWarn(TAG, `toggleHeartRate: deviceId is null, heartRate = ${this.heartRate}`);
         }
       }, DurationConstants.NOTIFY_DELAY_TIME)
    
         // 构造BLECharacteristic
         let arrayBufferC = ArrayBufferUtils.byteArray2ArrayBuffer([0x00, heartRate]);
         let characteristic: CharacteristicModel = {
           serviceUuid: BleConstants.UUID_SERVICE_HEART_RATE,
           characteristicUuid: BleConstants.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT,
           characteristicValue: arrayBufferC,
           descriptors: descriptors
         };
         // 通知的特征值消息
         let notifyCharacteristic: NotifyCharacteristicModel = {
           serviceUuid: BleConstants.UUID_SERVICE_HEART_RATE,
           characteristicUuid: BleConstants.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT,
           characteristicValue: characteristic.characteristicValue,
           confirm: false  // 对端不需要确认
         };
         // TODO: 知识点 server端特征值发生变化时,主动通知已连接的client设备。
         this.mGattServer.notifyCharacteristicChanged(deviceId, notifyCharacteristic, (err: BusinessError) => {
           if (err) {
             Log.showError(TAG, 'notifyCharacteristicChanged callback failed, err.code = ' + err.code + ", err.message =" + err.message);
           } else {
             Log.showInfo(TAG, 'notifyCharacteristicChanged callback success');
           }
         });
    
客户端
  1. 启动时请求蓝牙权限。源码参考BluetoothClient.ets。

    // 所需蓝牙权限
    const PERMISSION_LIST: Array<Permissions> = [
      'ohos.permission.APPROXIMATELY_LOCATION',
      'ohos.permission.LOCATION'
    ];
    
    // TODO 知识点: 获取蓝牙相关权限
    function reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext): void {
      const atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
      atManager.requestPermissionsFromUser(context, permissions).then((data) => {
        const granStatus: Array<number> = data.authResults;
        const length: number = granStatus.length;
        for (let i = 0; i < length; i++) {
          if (granStatus[i] === 0) {
    
          } else {
            return;
          }
        }
      })
    }
    
  2. 扫描设备。源码参考BluetoothClientModel.ets

    startBLEScan(): boolean {   
      if (!this.isBluetoothEnabled()) {
        Log.showInfo(TAG, `startBLEScan: bluetooth is disable.`);
        // 启动蓝牙服务
        this.enableBluetooth();
        promptAction.showToast({
          message: $r('app.string.ble_toast_enable_bluetooth'),
            duration: DurationConstants.DURATION_TIME
          });
        return false;
      }
      // 订阅搜索蓝牙服务
      this.onBLEDeviceFind(); 
      // 扫描蓝牙设备
      const ret = this.startBLEScanInner();
      return ret;
    }
    
  3. 连接设备。源码参考BluetoothClientModel.ets及connectInner。

    .onClick(() => {
      if (this.bluetoothDevice.connectionState === ConnectionState.STATE_DISCONNECTED) {
        // 连接蓝牙设备
        bluetoothViewModel.connect(this.bluetoothDevice);
      } else if (this.bluetoothDevice.connectionState === ConnectionState.STATE_CONNECTED) { 
        // 断开与蓝牙设备的连接
        bluetoothViewModel.disconnect();
      }
    })
    
    private connectInner(gattClientDevice: ble.GattClientDevice): boolean {
      try {
        if (!gattClientDevice) {
          Log.showWarn(TAG, `connectInner: mGattClientDevice is null`);
          return false;
        }
        // 订阅连接状态改变消息
        this.onBLEConnectionStateChange();
        // 订阅特征值改变消息
        this.onBLECharacteristicChange();
        // 开始连接
        gattClientDevice.connect();
        this.mConnectBluetoothDevice.connectionState = ConnectionState.STATE_CONNECTING;
        AppStorage.setOrCreate('connectBluetoothDevice', this.mConnectBluetoothDevice);
        return true;
      } catch (err) {
        Log.showError(TAG, `connectInner: err = ${err}`);
      }
      return false;
    }
    
  4. 向服务端发送‘通知心率跳动’特征值请求,侦听特征值变化数据。源码参考BLECharacteristicChange。

    // connect success, Starts discovering services.
    let services: Array<ble.GattService> = await this.mGattClientDevice!.getServices();
    Log.showInfo(TAG, `onBLEConnectionStateChange: services = ${JSON.stringify(services)}`);
    
    // Characteristic enable/disable indicate/notify
    let service: ble.GattService | undefined =
    services.find(item => item.serviceUuid === BleConstants.UUID_SERVICE_HEART_RATE);
    let characteristics: Array<ble.BLECharacteristic> = service!.characteristics;
    let characteristic: ble.BLECharacteristic | undefined =
    characteristics.find(item => item.characteristicUuid ===
    BleConstants.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT);
    Log.showInfo(TAG, `onBLEConnectionStateChange: characteristic = ${JSON.stringify(characteristic)}`);
    // TODO 知识点: 向服务端发送设置通知此特征值请求
    this.mGattClientDevice!.setCharacteristicChangeNotification(characteristic, true);
    let descriptors: Array<ble.BLEDescriptor> = characteristic!.descriptors;
    let descriptor: ble.BLEDescriptor | undefined =
    descriptors.find(item => item.descriptorUuid === BleConstants.UUID_DESCRIPTOR_HEART_RATE);
    Log.showInfo(TAG, `onBLEConnectionStateChange: descriptor = ${JSON.stringify(descriptor)}`);
    descriptor!.descriptorValue = ArrayBufferUtils.byteArray2ArrayBuffer([0x01, 0x00]);
    this.mGattClientDevice!.writeDescriptorValue(descriptor);
    
    // TODO 知识点: 订阅特征值变化事件
    this.mGattClientDevice.on('BLECharacteristicChange', (data: ble.BLECharacteristic) => {
    Log.showInfo(TAG, `onBLECharacteristicChange: data = ${JSON.stringify(data)}`);
    let characteristicValue: ArrayBuffer = data.characteristicValue;
    Log.showInfo(TAG,
    `onBLECharacteristicChange: characteristicValue.length = ${characteristicValue.byteLength}, characteristicValue = ${JSON.stringify(new Uint8Array(characteristicValue))}`);
    let byteArr = ArrayBufferUtils.arrayBuffer2ByteArray(characteristicValue);
    Log.showInfo(TAG, `byteArr = ${byteArr}`);
    let heartRate = byteArr[1];
    AppStorage.setOrCreate('heartRate', heartRate);
    })
    

高性能知识点

不涉及

工程结构&模块类型

bluetooth                                  // har类型
src/main/ets/
|---constants
|   |---BleConstants.ts                    // BLE常量
|   |---StyleConstants.ts                  // Style样式常量
|   |---DurationConstants.ts.ts            // 定时、延迟类常量
|---model
|   |---BluetoothDevice.ets                // 蓝牙设备model
|---pages
|   |---BluetoothView.ets                  // 场景首页,可选择进入客户端、服务端
|   |---BluetoothAdvertiser.ets            // 广播者角色(作为服务端)
|   |---BluetoothClient.ets                // 客户端连接页面
|   |---HeartRate.ets                      // 连接成功后,侦听到服务端的心率数据   
|---uicomponents
|   |---HeartRateGraph.ets                 // 实时心率图表
|   |---NavigationBar.ets                  // 顶部导航栏
|---uitls
|   |---ArrayBufferUtils.ts                // ArrayBuffer工具
|   |---DateUtils.ts                       // 日期工具
|   |---Log.ts                             // 日志工具
|   |---MathUtils.ts                       // Math工具,用于生成随机数
|---viewmodel
|   |---BluetoothClientModel.ets           // 开启蓝牙、扫描BLE、连接、断连等BLE接口
|   |---AdvertiserBluetoothViewModel.ets   // 开启蓝牙、开启蓝牙心率广播等

最后

小编在之前的鸿蒙系统扫盲中,有很多朋友给我留言,不同的角度的问了一些问题,我明显感觉到一点,那就是许多人参与鸿蒙开发,但是又不知道从哪里下手,因为体系杂乱无章,教授的人也多,无从选择。有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)路线、视频、文档用来跟着学习是非常有必要的。

如果你是一名有经验的资深Android移动开发、Java开发、前端开发、对鸿蒙感兴趣以及转行人员

鸿蒙 NEXT 全栈开发学习笔记 希望这一份鸿蒙学习文档能够给大家带来帮助~


 鸿蒙(HarmonyOS NEXT)最新学习路线

该路线图包含基础技能、就业必备技能、多媒体技术、六大电商APP、进阶高级技能、实战就业级设备开发,不仅补充了华为官网未涉及的解决方案

路线图适合人群:

IT开发人员:想要拓展职业边界
零基础小白:鸿蒙爱好者,希望从0到1学习,增加一项技能。
技术提升/进阶跳槽:发展瓶颈期,提升职场竞争力,快速掌握鸿蒙技术

2.视频教程+学习PDF文档

(鸿蒙语法ArkTS、TypeScript、ArkUI教程……)

 纯血版鸿蒙全套学习文档(面试、文档、全套视频等)

                   

总结

参与鸿蒙开发,你要先认清适合你的方向,如果是想从事鸿蒙应用开发方向的话,可以参考本文的学习路径,简单来说就是:为了确保高效学习,建议规划清晰的学习路线

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

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

相关文章

Cisco SD-WAN (Viptela) 20.15.1 发布,新增功能概览

Cisco SD-WAN (Viptela) version 20.15.1 ED - 软件定义广域网 Cisco SD-WAN powered by Viptela 请访问原文链接&#xff1a;https://sysin.org/blog/cisco-sd-wan-20/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org 支持 S…

SAP会计凭证导入ABAP开发模板+注意点—附带源码

会计凭证导入 前言:开发并不仅仅只要考虑实现的功能,只实现功能的是程序,考虑到使用场景的是工程。 使用bapi BAPI_ACC_DOCUMENT_CHECK 校验创建会计凭证的数据,报错和参数和正式创建一致。用途,防止产生错误的凭证,即使财务凭证可以冲销。 BAPI_ACC_DOCUMENT_POST 正式…

优化Python脚本,提高处理Office文档和数据的效率

目录 引言 性能优化的基本原则 1. 确定性能瓶颈 2. 优先优化最耗时的部分 3. 避免过度优化 4. 保持代码可读性 优化Python脚本处理Office文档和数据的方法 1. 使用高效的库和模块 2. 利用内置函数和高效的数据结构 3. 并发与异步编程 4. 缓存与重用 5. 自动化办公场…

8月更新速递丨秋风送爽,EasyTwin产品能力升级不停~

秋高气爽&#xff0c;金桂飘香&#xff0c;微风中已有几分凉意&#x1f342;&#xff5e;在过去的8月中&#xff0c;EasyTwin从**「多元异构数据融合」、「场景编辑及开发能力提升」**两方面&#xff0c;对产品进行了一轮全新的产品更新优化⬇️ 多元异构数据融合 GIS数据融…

Rust 赋能前端: 视频抽帧

❝ 如果你能想得到&#xff0c;就能做得到 大家好&#xff0c;我是柒八九。一个专注于前端开发技术/Rust及AI应用知识分享的Coder ❝ 此篇文章所涉及到的技术有 WebAssembly Rust wasm-bindgen 线程池 ViteReact/Vue(下面的内容&#xff0c;在各种前端框架中都用) 因为&#xf…

ZYNQ 7020 学习记录-2呼吸灯(模块化)

系列文章目录 1.点灯 2.呼吸灯&#xff08;模块化&#xff09; 文章目录 系列文章目录前言一、模块实例化二、呼吸灯1.原理解释2.按键消抖模块3.呼吸灯模块4.顶层模块5.上板验证 总结 前言 由于研究生课题组所需学习ZYNQ&#xff0c;以下是本人自学ZYNQ的学习记录&#xff0c…

MySQL数据库教程合集

课 程 推 荐我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448;入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448;虚 拟 环 境 搭 建 &#xff1a;&#x1…

【Qt】Qml界面中嵌入C++ Widget窗口

1. 目的 qml做出的界面漂亮&#xff0c;但是执行效率低&#xff0c;一直想找一个方法实现qml中嵌入c界面。现在从网上找到一个方法&#xff0c;简单试了一下貌似可行&#xff0c;分享一下。 2. 显示效果 3. 代码 3.1 工程结构 3.2 pro文件 需要添加widgets > QT quick …

数据集 VisDrone-Dataset 无人机检测跟踪数据集 >> DataBall

开源数据集 VisDrone-Dataset 无人机检测跟踪数据集-机器视觉目标跟踪 人工智能 深度学习 无人机或通用无人驾驶飞行器&#xff08;UAV&#xff09;配备相机后&#xff0c;已被迅速部署到包括农业、航拍、快速递送和监视在内的广泛应用中。因此&#xff0c;自动理解从这些平台收…

如何在Layui框架中实现列表操作后返回编辑页面并带参数刷新表单

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

C#匿名方法

在C#中&#xff0c;匿名函数是一种没有名字的方法&#xff0c;可以在代码中定义和使用。 我们已经提到过&#xff0c;委托是用于引用与其具有相同标签的方法。换句话说&#xff0c;可以使用委托对象调用可由委托引用的方法。 匿名方法&#xff08;Anonymous methods&#xff…

QGis二次开发 —— 1、Windows10搭建Vs2017-QGis环境(附Vs2017环境效果)(附:Qt助手加入QGis接口说明文档)

OSGeo4W简介 更高级的 QGIS 用户应该使用 OSGeo4W 包。此安装程序可以并行安装多个版本的 QGIS&#xff0c;并且还可以进行更高效的更新&#xff0c;因为每个新版本仅下载和安装更改的组件。      OSGeo4W 存储库包含许多来自 OSGeo 项目的软件。包括 QGIS 和所有依赖项&a…

Codeforces practice C++ 2024/9/11 - 2024/9/13

D. Mathematical Problem Codeforces Round 954 (Div. 3) 原题链接&#xff1a;https://codeforces.com/contest/1986/problem/D 题目标签分类&#xff1a;brute force&#xff0c;dp&#xff0c;greedy&#xff0c;implementation&#xff0c;math&#xff0c;two pointers…

威雅学校:解锁新学期!与威雅共赴秋实之约

【常州威雅】 九月的风&#xff0c;轻拂过青春的扉页; 新学期的篇章&#xff0c;正待你我提笔书写。 常州威雅再度迎来开学季&#xff0c;我们已准备好为威雅学子们提供一个充满活力与挑战的学习环境。在这里&#xff0c;新的故事将被书写&#xff0c;新的梦想将被点燃&#xf…

Van-ZYL算法

系统模型&#xff1a;由于观测散射矩阵一定是对称的&#xff08;系统压缩后的测量结果&#xff09;&#xff0c;且原S矩阵是互易的。此时系统由R T转置 Shv Svh 目标的互易 Ohv Ovh 接收数据的固有属性 R T转置 目标互易接收数据固有属性推导 本文串扰模型有两种理解。 1、…

这个桌面日历真不错 笔记 提醒 生日记录 打卡 翻译都有 真的太方便了!

这个桌面日历真不错 笔记 提醒 生日记录 打卡 翻译都有 真的太方便了&#xff01;日历产品非常的多&#xff0c;如何选择一个合适自己的桌面日历&#xff0c;这个很重要&#xff0c;今天小编给大家介绍这个芝麻日历&#xff0c;一起看下它有些什么功能&#xff0c;是不是你需要…

RFID射频模块(MFRC522 STM32)

目录 一、介绍 二、传感器原理 1.原理图 2.引脚描述 3.工作原理介绍 三、程序设计 main.c文件 MFRC522.h文件 MFRC522.c文件 四、实验效果 五、资料获取 项目分享 一、介绍 RC522 RFID射频模块是一款广泛应用于非接触式RFID系统中的核心组件&#xff0c;由NXP&…

大一新生以此篇开启你的算法之路

各位大一计算机萌新们&#xff0c;你们好&#xff0c;本篇博客会带领大家进行算法入门&#xff0c;给各位大一萌新答疑解惑。博客文章略长&#xff0c;可根据自己的需要观看&#xff0c;在博客中会有给大一萌新问题的解答&#xff0c;请不要错过。 入门简介&#xff1a; 算法…

STM32项目分享:智能风扇系统

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 PCB图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片&#xff1a; 哔哩哔哩视频链接&#xff1a; https://www.bilibili.com/video/BV1xw4m1Y7sA…

node解析dxf文件

1、dxf数据说明 DXF是一种开放的矢量数据格式&#xff0c;可以分为两类&#xff1a;ASCII格式和二进制格式&#xff1b;ASCII具有可读性好的特点&#xff0c;但占用的空间较大&#xff1b;二进制格式则占用的空间小、读取速度快。由于AutoCAD是最流行的CAD系统&#xff0c;DXF也…