HarmonyOS跨端迁移开发代码演示

news2024/9/24 11:31:36

目录

  • 说些废话
  • 开源代码
  • 环境
  • 代码
    • ability_main.xml
    • config.json
    • MainAbility.java
    • MainAbilitySlice.java
  • 测试

说些废话

    官方文档:跨端迁移开发指导(基于java开发)
    下面环境里写的两台真机我测试的时候无法正常产生回迁效果,所以实际上我是用的远程模拟器操作成功的,但是我懒得删我的设备信息了。
    模拟器不需要登录华为账号,但是需要在 设置-超级终端-允许被发现 处打开能够被附近设备发现。
图1

开源代码

    CrossSiteMigration

环境

    HUAWEI MatePad Pro 10.8英寸 2019款
    Mate 10 Pro 全网通版
    DevEco Studio 3.0.0.993 Release
    SDK 6(使用java)
    我看的《公共事件开发指导》更新于2022-10-28 18:02

代码

ability_main.xml

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:alignment="center"
    ohos:orientation="vertical">

    <Text
        ohos:id="$+id:text_register"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:layout_alignment="horizontal_center"
        ohos:text="注册流转服务"
        ohos:text_size="40vp"
        />
    <Text
        ohos:id="$+id:text_show"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:layout_alignment="horizontal_center"
        ohos:text="列出可流转的设备"
        ohos:scrollable="true"
        ohos:text_size="40vp"
        />
    <Text
        ohos:id="$+id:text_startMigration"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:layout_alignment="horizontal_center"
        ohos:text="开始迁移"
        ohos:scrollable="true"
        ohos:text_size="40vp"
        />
    <Text
        ohos:id="$+id:text_showParams"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:layout_alignment="horizontal_center"
        ohos:text="这里展示数据:无"
        ohos:scrollable="true"
        ohos:text_size="40vp"
        />
    <Text
        ohos:id="$+id:text_returnMigration"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:layout_alignment="horizontal_center"
        ohos:text="迁移回去"
        ohos:scrollable="true"
        ohos:text_size="40vp"
        />
</DirectionalLayout>

config.json

    长度问题只放module部分。

"module": {
    "package": "com.openvalley.cyj.migration",
    "name": ".MyApplication",
    "mainAbility": "com.openvalley.cyj.migration.MainAbility",
    "deviceType": [
      "phone",
      "tablet"
    ],
    "distro": {
      "deliveryWithInstall": true,
      "moduleName": "entry",
      "moduleType": "entry",
      "installationFree": false
    },
    "abilities": [
      {
        "skills": [
          {
            "entities": [
              "entity.system.home"
            ],
            "actions": [
              "action.system.home"
            ]
          }
        ],
        "name": "com.openvalley.cyj.migration.MainAbility",
        "description": "$string:mainability_description",
        "icon": "$media:icon",
        "label": "$string:entry_MainAbility",
        "launchType": "standard",
        "orientation": "unspecified",
        "visible": true,
        "type": "page"
      }
    ],
    "reqPermissions": [
      {
        "name": "ohos.permission.DISTRIBUTED_DATASYNC"
      }
    ]
  }

MainAbility.java

package com.openvalley.cyj.migration;

import com.openvalley.cyj.migration.slice.MainAbilitySlice;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.IAbilityContinuation;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.IntentParams;
import ohos.bundle.IBundleManager;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.security.SystemPermission;

public class MainAbility extends Ability implements IAbilityContinuation {
    private static final HiLogLabel LABEL_LOG = new HiLogLabel(HiLog.LOG_APP, 0x00001, MainAbility.class.getSimpleName());

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setMainRoute(MainAbilitySlice.class.getName());

        verifyAndRequestSelfPermission();
    }

    /**
     * 在此处验证和请求用户权限
     */
    private void verifyAndRequestSelfPermission() {
        try{
            //返回值0有,-1没有
            if(verifyCallingOrSelfPermission(SystemPermission.DISTRIBUTED_DATASYNC) == IBundleManager.PERMISSION_GRANTED){
//            if(verifySelfPermission(SystemPermission.LOCATION) == IBundleManager.PERMISSION_GRANTED){
                //如果有权限
            }else {
                //如果没授权就看这个权限能否动态授权
                if(canRequestPermission(SystemPermission.DISTRIBUTED_DATASYNC)){
                    //如果可以弹窗授权
                    requestPermissionsFromUser(new String[] {SystemPermission.DISTRIBUTED_DATASYNC}, 0x10001);
                }else {
                    //如果不能动态授权
                    return ;
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 授权的回调
     * @param requestCode
     * @param permissions
     * @param grantResults
     */
    @Override
    public void onRequestPermissionsFromUserResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsFromUserResult(requestCode, permissions, grantResults);
        if(requestCode == 0x10001){
            if(grantResults[0] == IBundleManager.PERMISSION_GRANTED){
                //如果授权成功(0)
                HiLog.info(LABEL_LOG, permissions[0] + "权限授权成功。");
            }else {
                //如果没有授权成功(-1)
                return ;
            }
        }
    }

    /**
     * 准备开始迁移的回调
     * @return
     */
    @Override
    public boolean onStartContinuation() {
        //返回值为true才发起迁移
        HiLog.info(LABEL_LOG, "MainAbility onStartContinuation");
        return true;
    }

    /**
     * 当保存数据(要迁移的数据)的回调
     * @param intentParams
     * @return
     */
    @Override
    public boolean onSaveData(IntentParams intentParams) {
        HiLog.info(LABEL_LOG, "MainAbility onSaveData");
        return true;
    }

    /**
     * 当恢复数据的回调(应该是被迁移的设备调用
     * @param intentParams
     * @return
     */
    @Override
    public boolean onRestoreData(IntentParams intentParams) {
        //返回为true代表恢复数据成功
        HiLog.info(LABEL_LOG, "MainAbility onRestoreData");
        return true;
    }

    /**
     * 迁移完成的回调
     * @param i
     */
    @Override
    public void onCompleteContinuation(int i) {
        HiLog.info(LABEL_LOG, " MainAbility onCompleteContinuation");
    }

    /**
     * 迁移过程中失败的回调
     */
    @Override
    public void onRemoteTerminated() {
        IAbilityContinuation.super.onRemoteTerminated();
        HiLog.info(LABEL_LOG, "MainAbility onRemoteTerminated");
    }

    /**
     * 回迁允许的情况下,远端中断
     * @param errorCode
     */
    @Override
    public void onFailedContinuation(int errorCode) {
        IAbilityContinuation.super.onFailedContinuation(errorCode);
        HiLog.info(LABEL_LOG, "MainAbility onFailedContinuation");
    }
}

MainAbilitySlice.java

package com.openvalley.cyj.migration.slice;

import com.openvalley.cyj.migration.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.ability.IAbilityContinuation;
import ohos.aafwk.ability.continuation.*;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.IntentParams;
import ohos.agp.components.Text;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

public class MainAbilitySlice extends AbilitySlice implements IAbilityContinuation {
    private static final HiLogLabel LABEL_LOG = new HiLogLabel(HiLog.LOG_APP, 0x00001, MainAbilitySlice.class.getSimpleName());

    Text text_register = null;
    Text text_show = null;
    Text text_startMigration = null;
    Text text_showParams = null;
    Text text_returnMigration = null;

    IContinuationRegisterManager continuationRegisterManager = null;
    IContinuationDeviceCallback continuationDeviceCallback = null;
    RequestCallback requestCallback = null;
    String jsonParams = null;
    int abilityToken = 0;
    String deviceId = null;

    String params = null;
    boolean isMigration = false;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);

        initContinuationRegisterManager();
        initComponent();
    }

    /**
     * 初始化注册管理类
     */
    private void initContinuationRegisterManager(){
       continuationRegisterManager = getContinuationRegisterManager();
       //设备的回调(是在列出了设备列表后,选择某个设备进行流转连接成功或者断开时调用)
       continuationDeviceCallback = new IContinuationDeviceCallback() {
           @Override
           public void onConnected(ContinuationDeviceInfo deviceInfo) {
               HiLog.info(LABEL_LOG, "onConnected()");
               deviceId = deviceInfo.getDeviceId();
               HiLog.info(LABEL_LOG, "onConnected() 连接成功。 deviceId = " + deviceId);
               continuationRegisterManager.updateConnectStatus(abilityToken, deviceId, DeviceConnectState.CONNECTED.getState(), requestCallback);
           }

           @Override
           public void onDeviceConnectDone(String s, String s1) {
               HiLog.info(LABEL_LOG, "onDeviceConnectDone()");
           }

           @Override
           public void onDisconnected(String deviceId) {
               HiLog.info(LABEL_LOG, "onDisconnected()");
           }

           @Override
           public void onDeviceDisconnectDone(String s) {
               HiLog.info(LABEL_LOG, "onDeviceDisconnectDone()");
           }
       };
       //请求的回调(注册到服务中心成功)
        requestCallback = new RequestCallback() {
            @Override
            public void onResult(int i) {
                if(i > 0){
                    //为了保证更新数据时这个值还在,所以在if里写
                    abilityToken = i;
                    HiLog.info(LABEL_LOG, "onResult() 注册成功。 abilityToken = " + abilityToken);
                }else {
                    HiLog.info(LABEL_LOG, "onResult() 其他操作。 abilityToken = " + i);
                }
            }
        };
    }

    /**
     * 初始化组件
     */
    private void initComponent(){
        text_register = (Text)findComponentById(ResourceTable.Id_text_register);
        text_register.setClickedListener(listen -> register());

        text_show = (Text)findComponentById(ResourceTable.Id_text_show);
        text_show.setClickedListener(listen -> show());

        text_startMigration = (Text)findComponentById(ResourceTable.Id_text_startMigration);
        text_startMigration.setClickedListener(listen -> startMigration());

        text_showParams = (Text)findComponentById(ResourceTable.Id_text_showParams);
        text_showParams.setText("这里展示数据:" + params);

        text_returnMigration = (Text)findComponentById(ResourceTable.Id_text_returnMigration);
        text_returnMigration.setClickedListener(listen -> returnMigration());
    }

    /**
     * 点击按钮进行流转服务注册
     */
    private void register(){
        if(continuationRegisterManager != null){
            HiLog.info(LABEL_LOG, "register() 开始注册。");
            continuationRegisterManager.register(getBundleName(), getExtraParams(), continuationDeviceCallback, requestCallback);
        }
    }

    /**
     * 展示可流转的设备
     */
    private void show(){
        if(continuationRegisterManager != null && abilityToken > 0){
            continuationRegisterManager.showDeviceList(abilityToken, getExtraParams(), requestCallback);
        }
    }

    /**
     * 开始迁移
     */
    private void startMigration(){
        if(continuationRegisterManager != null && deviceId != null){
            HiLog.info(LABEL_LOG, "startMigration() 开始迁移。");
//            continueAbility(deviceId);
            continueAbilityReversibly(deviceId);
            isMigration = true;
            HiLog.info(LABEL_LOG, "startMigration() 迁移结束。");
            //如果是不回迁的,这边的页面就可以销毁掉
//            terminateAbility();
        }
    }

    /**
     * 迁移回原设备
     */
    private void returnMigration(){
//        ContinuationState.
        try{
            boolean reverseContinueAbility = reverseContinueAbility();
            HiLog.info(LABEL_LOG, "reverseContinueAbility = " + reverseContinueAbility);
            isMigration = false;
        }catch (Exception e){
            HiLog.info(LABEL_LOG, "e = " + e.getMessage());
        }
    }

    /**
     * 获得注册时 额外的一些参数
     * @return
     */
    private ExtraParams getExtraParams(){
        ExtraParams extraParams = new ExtraParams();
        String[] devType = {ExtraParams.DEVICETYPE_SMART_PHONE, ExtraParams.DEVICETYPE_SMART_PAD};
        //显示的列表包含那些设备类型
        extraParams.setDevType(devType);
        //添加描述(没出来)
        extraParams.setDescription("这是一个描述。");
        //如果不写,就会默认以注册时的BundleName作为targetBundleName
        extraParams.setTargetBundleName(getBundleName());
        //设备过滤
        jsonParams = "\"{" +
                        "\"filter\":{" +
                            "\"commonFilter\":{" +
                                "\"system\":{" +
                                    //目标设备对应的HarmonyOS版本 要≥
                                    "\"harmonyVersion\":\"2.0.0\"" +
                                "}," +
//                                "}" +
                                //1为同账号,1|256为不同账号
                                "\"groupType\":\"1|256\"," +
                                //0x00000004需要在同一局域网下,0x00030004不需要在同一局域网下
                                "\"curComType\": 0x00030004," +
                                //为空就不做版本兼容性检查,要做版本兼容性检查时,需要传入目标应用包名。
                                "\"faFilter\":\"{" +
                                    "\"targetBundleName\":\"com.openvalley.cyj.migration\"" +
                                "}\"" +
                            "}" +
                        "}," +
                        "\"transferScene\":0," +
                        "\"remoteAuthenticationDescription\": \"拉起HiVision扫描弹框描述\"" +
                    "}\"";
//        HiLog.info(LABEL_LOG, jsonParams);
        extraParams.setJsonParams(jsonParams);
        return extraParams;
    }

    @Override
    public void onActive() {
        super.onActive();
    }

    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }

    @Override
    protected void onStop() {
        if(continuationRegisterManager != null && abilityToken > 0){
            continuationRegisterManager.unregister(abilityToken, requestCallback);
        }
    }

    /**
     * 准备开始迁移的回调
     * @return
     */
    @Override
    public boolean onStartContinuation() {
        //返回值为true才发起迁移
        HiLog.info(LABEL_LOG, "MainAbilitySlice onStartContinuation");
        return true;
    }

    /**
     * 当保存数据(要迁移的数据)的回调
     * @param intentParams
     * @return
     */
    @Override
    public boolean onSaveData(IntentParams intentParams) {
        HiLog.info(LABEL_LOG, "MainAbilitySlice onSaveData");
        intentParams.setParam("userName", "陈依劼");
        return true;
    }

    /**
     * 当恢复数据的回调(应该是被迁移的设备调用
     * @param intentParams
     * @return
     */
    @Override
    public boolean onRestoreData(IntentParams intentParams) {
        //返回为true代表恢复数据成功
        HiLog.info(LABEL_LOG, "MainAbilitySlice onRestoreData");
        Object userName = intentParams.getParam("userName");
        if(userName != null){
            params = (String)userName;
        }
        return true;
    }

    /**
     * 迁移完成的回调
     * @param i
     */
    @Override
    public void onCompleteContinuation(int i) {
        HiLog.info(LABEL_LOG, "MainAbilitySlice onCompleteContinuation");
    }

    /**
     * 迁移过程中失败的回调
     */
    @Override
    public void onRemoteTerminated() {
        HiLog.info(LABEL_LOG, "MainAbilitySlice onRemoteTerminated");
    }

    /**
     * 回迁允许的情况下,远端中断
     * @param errorCode
     */
    @Override
    public void onFailedContinuation(int errorCode) {
        IAbilityContinuation.super.onFailedContinuation(errorCode);
        HiLog.info(LABEL_LOG, "MainAbilitySlice onFailedContinuation");
    }
}

测试

    注意要先把想迁移到的设备的上的程序先授权。

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

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

相关文章

以太网 DHCP(DHCP的8种报文、DHCP配置、DHCP中继)

2.13.1 以太网 DHCP&#xff08;DHCP的8种报文、DHCP配置、DHCP中继&#xff09; DHCP-22.13.1 以太网 DHCP&#xff08;DHCP的8种报文、DHCP配置、DHCP中继&#xff09;一、DHCP的8种报文二、DHCP配置接口配置&#xff1a;全局配置&#xff1a;三、DHCP中继配置案例&#xff1…

游戏开发52课 渲染路径

4.6 渲染路径&#xff08;Rendering Path&#xff09; 4.6.1 经典顶点光&#xff08;Legacy Vertex Lit&#xff09; 严格来说&#xff0c;它也是前向渲染的一种&#xff0c;但有些引擎&#xff08;如Unity&#xff09;将它单独抽离出来。由于光照计算在顶点&#xff0c;所以…

微服务架构系列(一)之虚拟平台、分布式存储、高可用k8s集群环境搭建

一、物理机虚拟平台搭建 1、由实向需架构转换图&#xff08;每台物理机要求两块硬盘用来做分布式存储和系统盘&#xff0c;我的是10年前的老机器没啥大的要求&#xff09;&#xff1a; 2、系统安装去官网下载 Proxmox VE 7.x ISO Installer &#xff08;按需求选择版本&#x…

sublime text 4的安装/配置中文/更换配色方案

效果 安装 参考文章&#xff1a;Sublime Text v4.0(4143)安装方法 Sublime Text v4.0(4143)下载地址&#xff1a;https://www.sublimetext.com/download_thanks?targetwin-x64 安装软件找到软件安装位置&#xff0c;找到sublime_text.exe将sublime_text.exe 拖入16进制编辑…

[附源码]计算机毕业设计基于协同过滤的资讯推送平台Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

安卓玩机搞机技巧综合资源-----手机蝰蛇音效 杜比安装步骤 多种方式【九】

接上篇 安卓玩机搞机技巧综合资源------如何提取手机分区 小米机型代码分享等等 【一】 安卓玩机搞机技巧综合资源------开机英文提示解决dm-verity corruption your device is corrupt. 设备内部报错 AB分区等等【二】 安卓玩机搞机技巧综合资源------EROFS分区格式 小米红…

编程小白想转行互联网,想以python为入口,究竟可不可行?

前言 最近有些朋友私信过我这个问题&#xff0c;很多编程小白想从事或转行互联网&#xff0c;想以Python为切入口&#xff0c;究竟可不可行&#xff1f; 以我看到的一些小伙伴的学习经历来说&#xff0c;虽说学会Python不能够马上胜任一些工作&#xff0c;但这可能是你离互联…

一例Trickbot家族js下载器的分析

样本信息 MD5: e36380d824811bc28fbc26ea84c1a868 SHA1: 19d5fc16cfabae3b3c26bbb4f5798da42733a2fa SHA256: 16429e95922c9521f7a40fa8f4c866444a060122448b243444dd2358a96a344c SHA512: 6c6f323893870536822a2aa2aebe783379906081fcf004dd04cb40cc1109c3452d39b548ac8b2a654…

安卓APP源码和设计报告——导航系统

演示答辩发言稿&#xff1a; 注意&#xff1a;1.在mainfest.xml文档中添加访问权限即一系列<uses-permission>元素使用Android中提供的权限。比如百度地图的使用联网的情况下需要网络功能权限。 2.在Stings.xml中添加一些字符串数组&#xff0c;离线数据管理、简体繁体…

python---数据容器

目录 环境安装 python语法 打印语句 注释 变量 变量声明 变量类型 boolean类型 占位符 控制数据精度 输入输出 条件控制 循环语句 while循环 for循环 函数 None类型 数据容器 列表 元组 字符串 序列 集合 字典 环境安装 1、安装python运行环境 Welcome t…

swiftui 中的app和 Scenes有什么,他们是什么关系

app和 Scenes有什么,他们是什么关系 SwiftUI 中的 app 和 Scenes 是两个相关的概念,它们都与应用程序的用户界面有关。 app 是指使用 SwiftUI 框架开发的应用程序,它包含了用户界面的所有内容和逻辑。在 SwiftUI 中,app 的界面通常由多个视图组成,每个视图都可以显示不同…

使用声网 SDK 构建 Piloteer 助盲服务平台的最佳实践

前言 在今年声网主办的「RTE2022 编程挑战赛」中&#xff0c;数支队伍经过一个多月的努力开发&#xff0c;很多优秀的作品最终突出重围&#xff0c;斩获大奖。本文由RTE2022编程挑战赛获奖者之一李新春撰写&#xff0c;他主要围绕获奖作品「Piloteer助盲服务平台」分享了开发的…

用HarmonyOS ArkUI实现点赞美女翻牌动效

本文演示如果用HarmonyOS的ArkUI来实现一个点赞的动画效果。体验HarmonyOS 3最新的API 9&#xff0c;欢迎大家一起参与构建这个万物互联的时代&#xff01; 活动主页 HarmonyOS线上Codelabs挑战赛已经开启&#xff0c;该系列挑战赛将围绕HarmonyOS的基础组件和容器组件、三方…

用Clash解决Python安装模块慢的问题

已经开了代理了&#xff0c;但如果没有使用全局模式的话&#xff0c;Python模块下载速度依然非常慢&#xff0c;只有几十K。使用全局模式是可以解决这个问题&#xff0c;但同时访问国内的一些网站又会速度特别慢&#xff0c;甚至打不开。 比如我们亲爱的知乎就会显示&#xff…

Vue项目初始化

1.创建脚手架&#xff1a; cmd控制台切换到指定的目录命令&#xff1a; vue create 项目名 然后cd到项目里运行&#xff1a; npm run serve 生成目录 2.配置&#xff1a; &#xff08;1&#xff09;关闭eslint 防止定义没用带来的报错 在vue.config.js中&#xff1a; 配置&…

Codeforces Global Round 19 D. Yet Another Minimization Problem

翻译&#xff1a; 给定两个数组&#x1d44e;和&#x1d44f;&#xff0c;长度都为&#x1d45b;。 选择索引&#x1d456;(1≤&#x1d456;≤&#x1d45b;)&#xff0c;将&#x1d44e;&#x1d456;和&#x1d44f;&#x1d456;交换。 让我们来定义数组的成本&#x1d…

Java连接SQL Server数据库的详细操作流程

Java连接SQL Server数据库的详细操作流程 一.明确JDK版本和下载驱动 1.1 JDK版本查看 win r输入cmd,命令窗口输入java --version 1.2 SQL Server官网下载驱动 SQL Server驱动下载直达地址 下载完成后解压到自己熟悉的目录&#xff0c;不出意外的话你会看到以下文件 1.3 …

IO流~字符流

字符流 为什么会出现字符流 由于字节流操作中文不是特别的方便&#xff0c;所以Java就提供字符流 字符流 字节流 编码表 用字节流复制文本文件时&#xff0c;文本文件也会有中文&#xff0c;但是没有问题&#xff0c;原因是最终底层操作会自动进行字节拼接成中文&#xf…

基于Java的学生竞赛管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

数据库面试题1-数据库基本概念、常用SQL语言

题1&#xff1a;什么是数据库 数据库&#xff08;Database&#xff09; 是保存有组织的数据的容器&#xff08;通常是一个文件或一组文件&#xff09;&#xff0c;是通过 数据库管理系统&#xff08;DataBase- Management System&#xff0c;DBMS&#xff09; 创建和操纵的容器…