Qt通过Doc模式读取XML并设计一个增删改查方便的一个操作类

news2025/7/26 19:26:43

前言

如果对开源库TinyXml有兴趣的可以去看看这篇文章。
C++使用TinyXml(开源库)读取*.XMl文件

目录

  • 前言
  • DOC 文档对象模型
  • QtXML基本结构
  • 操作XML
    • 部署环境
    • 添加信息头
    • 读取XML文件
    • 添加根节点
    • 添加一个没有属性的节点
    • 添加一个有属性的节点
    • 添加一个元素节点
    • 给节点单独设置属性
    • 删除所有同名节点
    • 删除所有同名带属性的节点
    • 递归删除所有同名的节点
    • 保存XML
    • 获取节点元素
    • 获取节点元素的值
    • 获取该节点的属性值
  • 完整代码

DOC 文档对象模型

文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展置标语言的标准编程接口。它是一种与平台和语言无关的应用程序接口(API),它可以动态地访问程序和脚本,更新其内容、结构和www文档的风格(HTML和XML文档是通过说明部分定义的)。文档可以进一步被处理,处理的结果可以加入到当前的页面。

DOM是一种基于树的API文档,它要求在处理过程中整个文档都表示在存储器中。另外一种简单的API是基于事件的SAX,它可以用于处理很大的XML文档,由于大,所以不适合全部放在存储器中处理。

先来了解一下xml基本要素:
在这里插入图片描述

QtXML基本结构

下面列出了Qt处理xml的一些类以及说明,加粗表示是常用。

类名说明
QDomAttrThe QDomAttr class represents one attribute of a QDomElement
QDomNodeThe QDomNode class is the base class for all the nodes in a DOM tree.
QDomTextThe QDomText class represents text data in the parsed XML document.
QDomElementThe QDomElement class represents one element in the DOM tree.
QDomCDATASectionThe QDomCDATASection class represents an XML CDATA section
QDomCharacterDataThe QDomCharacterData class represents a generic string in the DOM
QDomCommentThe QDomComment class represents an XML comment
QDomDocumentThe QDomDocument class represents an XML document
QDomDocumentFragmentThe QDomDocumentFragment class is a tree of QDomNodes which is not usually a complete QDomDocument.
QDomEntityThe QDomEntity class represents an XML entity.

操作XML

部署环境

通过Qt Create创建一个工程。然后在*.pro配置文件中添加xml model。
在这里插入图片描述
在添加Qt解析xml相关的头文件

#include <QtXml>
#include <QDomDocument>

添加信息头

	// xml文档
	QDomDocument* m_Doc = new QDomDocument(); 
	
    // 创建XML处理类,通常用于处理第一行描述信息
    QDomProcessingInstruction instruction;

    std::string note =  "version=1.0 encoding=utf-8";

    // 创建XML头部格式
    instruction = m_Doc->createProcessingInstruction(QString::fromStdString(type), QString::fromStdString(note));

    // 添加到XML文件中
    m_Doc->appendChild(instruction);

读取XML文件

    // 打开文件
    QFile m_File = new QFile("./1.xml");

    if (false == m_File->open(mode))
    {
        QMessageBox::information(NULL, u8"提示", u8"文件打开失败!");
        return;
    }

    // 将doc与file关联起来
    // 这个函数从IO设备dev中读取XML文档,如果内容被成功解析,则返回true;否则返回false。
    if (false == m_Doc->setContent(m_File))
    {
        QMessageBox::information(NULL, u8"提示", u8"操作的文件不是XML文件!");
        m_File->close();
        return ;
    }

添加根节点

通过createElement方法创建的第一个子节点就是根节点。然后通过appendChild方法将创建的节点添加到doc中。

    // 创建根节点
    QDomElement rootNode = m_Doc->createElement(rootName);

    // 添加到XML文件中
    m_Doc->appendChild(rootNode);

添加一个没有属性的节点

添加一个没有属性的节点的方法和添加根节点的方法一致。

    // 创建根节点
    QDomElement rootNode = m_Doc->createElement(rootName);

    // 添加到XML文件中
    m_Doc->appendChild(rootNode);

添加一个有属性的节点

    std::list<std::pair<std::string, std::string>> Attribute{{"ID","2"},{"name","张三"}};
    QDomElement node = m_Doc->createElement(nodeName);

    // 给节点创建属性
    for(const auto& elem : Attribute)
    {
        // 参数一是字符串,参数二可以是任何类型
        node.setAttribute(QString::fromStdString(elem.first), QString::fromStdString(elem.second));
    }

    rootNode.appendChild(node);

添加一个元素节点

    // 创建子元素
    QDomElement node = m_Doc->createElement(nodeName);

    // 设置尖括号中的值
    QDomText text = m_Doc->createTextNode(value);

    // 添加关系
    node.appendChild(text);
    root.appendChild(node);

给节点单独设置属性

setAttribute方法设置节点的属性名和属性值。

    QDomElement elemNode = m_Doc->createElement(QString::fromStdString(name));

    elemNode.setAttribute(QString::fromStdString(name), QString::fromStdString(value));

    node.appendChild(elemNode);

删除所有同名节点

removeChild方法使用需要注意

看下面官方文档说明

Removes oldChild from the list of children. oldChild must be a direct child of this node.
Returns a new reference to oldChild on success or a null node on failure.

类似于C++容器存在迭代器失效问题。所以我这里就从后向前删除了。

    // 获取节点名字为Book的所有节点
    QDomNodeList nodes = m_Doc->elementsByTagName(nodeName);

    for (int i = nodes.size() - 1; i >= 0; i--)
    {
        // 获取节点
        QDomElement element = nodes.at(i).toElement();
        
         //   所以 要么从后向前删除 要么就需要重新指定新节点的位置
        root.removeChild(element);
    }

删除所有同名带属性的节点

    QDomNodeList nodes = m_Doc->elementsByTagName(nodeName);

    for (int i = 0; i < nodes.count(); i++)
    {
        // 获取节点
        QDomElement element = nodes.at(i).toElement();

        bool isFind {true};
        for(const auto& elem : attribute)
        {
            // 进行判断(返回属性的值进行判断)
            if (element.attribute(QString::fromStdString(elem.first)) != QString::fromStdString(elem.second))
            {
                isFind = false;
            }
        }
        if(true == isFind)
        {
            root.removeChild(nodes.at(i));
        }
    }

递归删除所有同名的节点

    // 获取节点名字为Book的所有节点
    QDomNodeList nodes = m_Doc->elementsByTagName(QString::fromStdString(nodename));

    // QDomElement root = GetRootNode();

    for (int i = nodes.size() - 1; i >= 0; i--)
    {
        // 获取节点
        QDomElement element = nodes.at(i).toElement();
        
        // 获取父节点
        QDomNode fNode = element.parentNode();
        
        fNode.removeChild(element);
    }

保存XML

    QFile* m_File= new QFile(fileName);
    if (false == m_File->open(QFileDevice::WriteOnly | QFileDevice::Truncate))
    {
        QMessageBox::information(NULL, "提示", "文件打开失败!");
        return;
    }
    QTextStream stream(m_File);
    m_Doc->save(stream, retract);

获取节点元素

if (node.toElement().tagName() == name)
{
    return node;
}

获取节点元素的值

if (node.toElement().tagName() == name)
{
    return node.toElement().text().toStdString();
}

获取该节点的属性值

key为属性名

if (false == node.isNull() && true == node.toElement().hasAttribute(key))
{
value = node.toElement().attributeNode(key).value();
}

完整代码

注:必须支持C++17

OperateXML.h

#ifndef OPERATEXML_H
#define OPERATEXML_H

// 读取xml必须要包含的
#include <QtXml>
#include <QDomDocument>

#include <QIODevice>
#include <QMessageBox>
//#include <QtCore5Compat/QTextCodec>

#include <string>
#include <map>

class OperateXML
{
public:

    explicit OperateXML(/*std::string filename = std::string("")*/);
    ~OperateXML();

    // 创建一个xml文件
    bool CreateXmlFile(std::string filename = std::string(""), QIODevice::OpenMode mode = QFileDevice::WriteOnly | QFileDevice::Truncate);

    // 添加一个信息头
    void CreateXmlHeader(std::string type = std::string("xml"), std::string version = "1.0", std::string encoding = std::string("UTF-8"));

    // 加载已有的xml文件
    bool LoadXml(std::string filename, QIODevice::OpenMode mode = QFileDevice::ReadOnly);

    // 获取根节点 Stu
    QDomElement GetRootNode();

    // 创建一个根节点  Stu
    QDomElement CreateXmlRootNode(std::string rootName = std::string("root"));

    // 添加一个没有属性的节点  <StuInfo/>  Stu StuInfo
    QDomElement AddNoAttributesNode(QDomElement fNode, std::string nodeName);

    // 添加一个有属性的节点  <StuInfo ID = "1">  Stu StuInfo  ID 1  Name 张三
    QDomElement AddAttributesNode(QDomElement fNode, std::string nodeName,
                                  std::list<std::pair<std::string, std::string>> Attribute);

    // 添加元素节点
    QDomElement  AddElementNode(QDomElement fNode, std::string nodeName, std::string value);

    // 设置节点属性
    QDomElement SetNodeAttribute(QDomElement node, std::string name, std::string value);

    // 删除节点 删除当前节点下的所有名为nodename的节点
    void DeleteNodes(QDomElement fNode, std::string nodename);

    // 删除节点 删除当前节点下的所有名为nodename的节点 且属性值相同
    void DeleteNode(QDomElement fNode, std::string nodename,
                    std::list<std::pair<std::string, std::string>> attribute);

    // 删除节点 删除所有节点下名为nodename的节点
    void DeleteNodes(std::string nodename);

     // 删除节点 删除所有节点下名为nodename的节点 且属性值相同
    void DeleteNode(std::string nodename, std::list<std::pair<std::string, std::string>> attribute);

    // 保存Xml  进位空格数
    void SaveXml(int retract = 4);

    // 获取当前节点以及同级下的兄弟节点 且名为name的节点  如果为第一个孩子节点记得传入第三个参数为true
    QDomElement GetElem(QDomElement& node, std::string name, bool first = false);
    QDomElement GetElem(QDomElement& node, QString name, bool first = false);


    // 获取当前节点以及同级下的兄弟节点 且名为name的节点的值
    std::string GetElemValue(QDomElement& node, std::string name, bool first = false);
    QString GetElemValue(QDomElement& node, QString name, bool first = false);


    // 获取 该节点指定的 属性节点值
    std::string GetElemAttributeValue(QDomElement node, std::string key);
    QString GetElemAttributeValue(QDomElement node, QString key);
private:
    QDomDocument* m_Doc;
    QFile* m_File;
    std::string m_FileName;

};

#endif // OPERATEXML_H 

OperateXML.cpp

#include "OperateXML.h"

OperateXML::OperateXML(/*std::string filename*/)
    : m_Doc(new QDomDocument())
    , m_File{nullptr}
{
}

OperateXML::~OperateXML()
{
    if(nullptr != m_Doc)
    {
        delete m_Doc;
        m_Doc = nullptr;
    }
    if(nullptr != m_File)
    {
        m_File->close();
        delete m_File;
        m_File = nullptr;
    }
}

bool OperateXML::CreateXmlFile(std::string filename, QIODevice::OpenMode mode)
{
    if(true == filename.empty())
    {
        QMessageBox::information(NULL, u8"提示", u8"文件名为空!");
        return false;
    }

    if(nullptr != m_File)
    {
        delete m_File;
        m_File = nullptr;
    }

    m_File = new QFile(QString::fromStdString(filename));

    if(false == m_File->open(mode))
    {
        QMessageBox::information(NULL, u8"提示", u8"文件打开或创建失败!");
        return false;
    }

    if(false == m_File->isOpen())
    {
        QMessageBox::information(NULL, u8"提示", u8"文件打开或创建失败!");
        return false;
    }

    return true;
}

void OperateXML::CreateXmlHeader(std::string type, std::string version, std::string encoding)
{
    // 创建XML处理类,通常用于处理第一行描述信息
    QDomProcessingInstruction instruction;

    std::string note =  std::string("version=\"") + version + std::string("\"  ") +
            std::string("encoding=\"") + encoding + std::string("\"");

    // 创建XML头部格式
    instruction = m_Doc->createProcessingInstruction(QString::fromStdString(type), QString::fromStdString(note));

    // 添加到XML文件中
    m_Doc->appendChild(instruction);
}

bool OperateXML::LoadXml(std::string filename, QIODevice::OpenMode mode)
{
    // 打开文件
    m_File = new QFile(QString::fromStdString(filename));

    if (false == m_File->open(mode))
    {
        QMessageBox::information(NULL, u8"提示", u8"文件打开失败!");

        return false;
    }

    // 将doc与file关联起来
    // 这个函数从IO设备dev中读取XML文档,如果内容被成功解析,则返回true;否则返回false。
    if (false == m_Doc->setContent(m_File))
    {
        QMessageBox::information(NULL, u8"提示", u8"操作的文件不是XML文件!");
        m_File->close();
        return false;
    }

    return true;
}

QDomElement OperateXML::GetRootNode()
{
    QDomElement root = m_Doc->documentElement();

    return root;
}

QDomElement OperateXML::CreateXmlRootNode(std::string rootName)
{
    // 创建根节点
    QDomElement rootNode = m_Doc->createElement(QString::fromStdString(rootName));

    // 添加到XML文件中
    m_Doc->appendChild(rootNode);


    return rootNode;
}

QDomElement OperateXML::AddNoAttributesNode(QDomElement fNode, std::string nodeName)
{
    if(true == fNode.isNull())
    {
        return QDomElement();
    }
    QDomElement node = m_Doc->createElement(QString::fromStdString(nodeName));

    fNode.appendChild(node);



    return node;
}

QDomElement OperateXML::AddAttributesNode(QDomElement fNode, std::string nodeName,
                                          std::list<std::pair<std::string, std::string>> Attribute)
{
    QDomElement node = m_Doc->createElement(QString::fromStdString(nodeName));

    // 给节点创建属性
    for(const auto& elem : Attribute)
    {
        // 参数一是字符串,参数二可以是任何类型
        node.setAttribute(QString::fromStdString(elem.first), QString::fromStdString(elem.second));
    }

    fNode.appendChild(node);

    return node;
}

QDomElement OperateXML::AddElementNode(QDomElement fNode, std::string nodeName, std::string value)
{
    // 创建子元素
    QDomElement node = m_Doc->createElement(QString::fromStdString(nodeName));

    // 设置尖括号中的值
    QDomText text = m_Doc->createTextNode(QString::fromStdString(value));

    // 添加关系
    node.appendChild(text);
    fNode.appendChild(node);

    return node;
}

QDomElement OperateXML::SetNodeAttribute(QDomElement node, std::string name, std::string value)
{
    QDomElement elemNode = m_Doc->createElement(QString::fromStdString(name));

    elemNode.setAttribute(QString::fromStdString(name), QString::fromStdString(value));

    node.appendChild(elemNode);

    return node;
}

void OperateXML::DeleteNodes(QDomElement fNode, std::string nodename)
{
    // 获取节点名字为Book的所有节点
    QDomNodeList nodes = m_Doc->elementsByTagName(QString::fromStdString(nodename));

    for (int i = nodes.size() - 1; i >= 0; i--)
    {
        // 获取节点
        QDomElement element = nodes.at(i).toElement();
        /*
         * Removes oldChild from the list of children. oldChild must be a direct child of this node.
            Returns a new reference to oldChild on success or a null node on failure.

            所以 要么从后向前删除 要么就需要重新指定新节点的位置
         */
        fNode.removeChild(element);
    }

}

void OperateXML::DeleteNode(QDomElement fNode, std::string nodename, std::list<std::pair<std::string, std::string>> attribute)
{
    QDomNodeList nodes = m_Doc->elementsByTagName(QString::fromStdString(nodename));

    for (int i = 0; i < nodes.count(); i++)
    {
        // 获取节点
        QDomElement element = nodes.at(i).toElement();

        bool isFind {true};
        for(const auto& elem : attribute)
        {
            // 进行判断(返回属性的值进行判断)
            if (element.attribute(QString::fromStdString(elem.first)) != QString::fromStdString(elem.second))
            {
                isFind = false;
            }
        }
        if(true == isFind)
        {
            fNode.removeChild(nodes.at(i));
        }
    }
}

void OperateXML::DeleteNodes(std::string nodename)
{
    // 获取节点名字为Book的所有节点
    QDomNodeList nodes = m_Doc->elementsByTagName(QString::fromStdString(nodename));

    // QDomElement root = GetRootNode();

    for (int i = nodes.size() - 1; i >= 0; i--)
    {
        // 获取节点
        QDomElement element = nodes.at(i).toElement();
        /*
         * Removes oldChild from the list of children. oldChild must be a direct child of this node.
            Returns a new reference to oldChild on success or a null node on failure.

            所以 要么从后向前删除 要么就需要重新指定新节点的位置
         */
        QDomNode fNode = element.parentNode();
        fNode.removeChild(element);
    }
}

void OperateXML::DeleteNode(std::string nodename, std::list<std::pair<std::string, std::string> > attribute)
{
    QDomNodeList nodes = m_Doc->elementsByTagName(QString::fromStdString(nodename));

    for (int i = 0; i < nodes.count(); i++)
    {
        // 获取节点
        QDomElement element = nodes.at(i).toElement();

        bool isFind {true};
        for(const auto& elem : attribute)
        {
            // 进行判断(返回属性的值进行判断)
            if (element.attribute(QString::fromStdString(elem.first)) != QString::fromStdString(elem.second))
            {
                isFind = false;
            }
        }
        if(true == isFind)
        {
            QDomNode fNode = element.parentNode();
            fNode.removeChild(nodes.at(i));
        }
    }
}

void OperateXML::SaveXml(int retract)
{
    m_File->close();
    if (false == m_File->open(QFileDevice::WriteOnly | QFileDevice::Truncate))
    {
        QMessageBox::information(NULL, "提示", "文件打开失败!");
        return;
    }
    QTextStream stream(m_File);
    m_Doc->save(stream, retract);
}

QDomElement OperateXML::GetElem(QDomElement& node, std::string name, bool first)
{
    if(true == first)
    {
        node = node.firstChild().toElement();
    }
    while(false == node.isNull())
    {
        if (node.toElement().tagName() == QString::fromStdString(name))
        {
            return node;
        }
        node = node.nextSibling().toElement();
    }
    return QDomElement();
}

QDomElement OperateXML::GetElem(QDomElement &node, QString name, bool first)
{
    if(true == first)
    {
        node = node.firstChild().toElement();
    }
    while(false == node.isNull())
    {
        // qDebug() << node.toElement().tagName();
        if (node.toElement().tagName() == name)
        {
            return node;
        }
        node = node.nextSibling().toElement();
    }
    return QDomElement();
}

std::string OperateXML::GetElemValue(QDomElement& node, std::string name, bool first)
{
    if(true == first)
    {
        node = node.firstChild().toElement();
    }
    while(false == node.isNull())
    {
        // qDebug() << node.toElement().tagName();
        if (node.toElement().tagName() == QString::fromStdString(name))
        {
            return node.toElement().text().toStdString();
        }
        node = node.nextSibling().toElement();
    }
    return std::string();
}

QString OperateXML::GetElemValue(QDomElement &node, QString name, bool first)
{
    if(true == first)
    {
        node = node.firstChild().toElement();
    }
    while(false == node.isNull())
    {
        // qDebug() << node.toElement().tagName();
        if (node.toElement().tagName() == name)
        {
            return node.toElement().text();
        }
        node = node.nextSibling().toElement();
    }
    return QString();
}
std::string OperateXML::GetElemAttributeValue(QDomElement node, std::string key)
{
    std::string value;

    if (false == node.isNull() && true == node.toElement().hasAttribute(QString::fromStdString(key)))
    {
        value = node.toElement().attributeNode(QString::fromStdString(key)).value().toStdString();
    }
    return value;
}

QString OperateXML::GetElemAttributeValue(QDomElement node, QString key)
{
    QString value;

    if (false == node.isNull() && true == node.toElement().hasAttribute(key))
    {
        value = node.toElement().attributeNode(key).value();
    }
    return value;
}

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

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

相关文章

开源软件安全与应对策略探讨 - Java 机密计算技术应用实践

据统计&#xff0c;90% 以上的应用都在使用第三方软件库&#xff0c;这些软件大部分都是开源的。与此同时&#xff0c;有超过一半的全球 500 强公司都在使用存在漏洞的开源软件。这幅漫画生动的描述了一个大型应用软件的组件架构&#xff0c;它可能建立在一个极其脆弱的开源组件…

SpringBoot整合Swagger2+Knife4j,注解使用

SpringBoot整合Swagger2Knife4j,注解使用 文章目录SpringBoot整合Swagger2Knife4j,注解使用前言一、swagger是什么&#xff1f;二、使用步骤1.引入库2.使用swagger的相关注解总结前言 swagger和postman都是后端编写的测试接口使用方式&#xff0c;由于实际开发的需求和使用习惯…

基于springboot的汽车租赁管理系统的设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

pytorch实现mnist手写数字识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f366; 参考文章地址&#xff1a; 365天深度学习训练营-第P1周&#xff1a;mnist手写数字识别&#x1f356; 作者&#xff1a;K同学啊一、 前期准备 1. 设置GPU import torch import torch.nn a…

MySQL8.0爬坑二三事

【下载】 地址&#xff1a;MySQL :: Download MySQL Community Serverhttps://dev.mysql.com/downloads/mysql/ 【安装】 1.解压复制下面一堆文件到你需要的路径 2.如下图添加一个data文件夹&#xff0c;专门来放数据 3.新建一个my.ini的配置文件&#xff0c;里面内如如下 4…

如何将草料二维码收集到的表单信息同步至腾讯文档

在进行工业巡检场景如消防栓检查时&#xff0c;需要到达巡检地点后&#xff0c;扫描草料二维码&#xff0c;然后填写巡检的结果。事后&#xff0c;还需要有一个工作人员将草料二维码中的信息手动复制粘贴至腾讯文档中。那么能不能将我们信息填写后&#xff0c;自动就汇总至腾讯…

检索系统设计方案(重构)

记一次系统重构设计背景介绍设计步骤架构图介绍架构设计注意点总结背景介绍 搜索链路主要部分 搜索引擎链路都包含这三部分&#xff0c;数据源、搜索引擎服务、搜索业务。 是不是很简单&#xff0c;感觉搜索也没那么难&#xff1f; 搜索链路确实都包括这三部分&#xff0c;…

编程参考 - 编程中给变量起名时如何选择前缀,以及匈牙利命名法等

我最开始当程序员用C语言写代码&#xff0c;公司里推行编码规范&#xff0c;变量的前缀都是有规定的。 比如整型变量&#xff0c;前面都是 u8Name, i8Name, u16Name, i16Name之类的。 尤其是嵌入式编程&#xff0c;涉及到代码移植的问题&#xff0c;最好使用和平台无关的类型定…

显存优化综述

显存优化综述动态图和静态图静态图显存优化动态图显存优化DTR问题解决办法重计算的局限性Cooprecomputable in placeop-guided allocationLayout-aware Eviction实验效果消耗的时间显存碎片率搜索时间动态图和静态图 动态图是边计算边搭建计算图&#xff0c;中间结果一目了然。…

Quasar搭建教程初体验

文章目录一、Quasar框架介绍二、搭建一个简单的Quasar程序1、Quasar CLI安装2、创建Quasar应用程序3、运行Quasar三、使用Quasar开发SSR四、使用Quasar开发桌面应用(Electron)1、添加Quasar Electron模式2、运行开发五、使用Quasar移动应用(Capacitor)1、下载安装AndroidStudio…

测试用例设计方法之判定表法

概念&#xff1a; 等价类&#xff0c;边界值分析法一般是对单一输入进行测试用例分析的方法。 判定表是对其的一种补充&#xff0c;对于多种输入之间存在的组合关系并且对应执行不同动作&#xff0c;进行测试用例的分析的方法。 应用场景&#xff1a; 当一个界面中有多个控…

数据集成产品分析

数据集成产品分析 数据集成产品致力于异构数据源之间的数据交换与汇聚&#xff0c;该类产品是数据中台建设的第一环节&#xff0c;笔者将通过两篇文章对数据集成产品进行分析。 数据同步&#xff0c;又称为数据集成、数据迁移&#xff0c;主要用于实现不同系统间的数据流转。…

C++之结构、枚举

结构 C提供了struct关键字可以将不同类型封装在一起,形成结构体. 数组中存储的是相同类型的数据&#xff0c;而结构中可以存储不同类型的数据。定义结构就像定义一个新的数据类型一样. 结构是类的基石 结构的定义、声明与初始化 定义语法格式: struct 结构体类型名 { 成员…

深入浅出PyTorch——PyTorch生态简介+模型部署

1. 生态简介 介绍PyTorch生态在图像、视频、文本等领域中的发展&#xff0c;针对某个领域选择其中有代表性的一个工具包进行详细介绍 1.1 torchvision torchvision包含了在计算机视觉中常常用到的数据集&#xff0c;模型和图像处理的方式 函数作用 torchvision.datasets * 计…

PLC中ST编程的无符号数逻辑运算

AND与运算&#xff0c;两个数据每个位进行与运算&#xff0c;只有当相同位的值都为1时&#xff0c;那个位结果为1&#xff1b; 2# 0000 0100 1101 0010 2# 0001 0110 0010 1110 AND 2# 0000 0100 0000 0010 OR或运算&#xff0c;两个数据每个位进行或运算&#xff0c;只…

国产化Kettle、JDK、MySQL下载安装操作步骤

一、Kettle下载安装 &#xff08;一&#xff09;、kettle的下载 1、登录https://sourceforge.net/projects/pentaho/ 2、点击“Files”&#xff0c;进入Home / Data Integration 目录&#xff0c;下载需要的版本&#xff0c;以6.1为例。 3、点击“pdi-ce-6.1.0.1-196.zip”…

自制操作系统日记(8):变量显示

代码仓库地址&#xff1a;https://github.com/freedom-xiao007/operating-system 简介 上篇中&#xff0c;我们显示了静态的字符串在桌面上&#xff0c;本篇进一步探索&#xff0c;能将定义的整型变量的值显示在桌面上 探索历程说明 本来想着应该是一两天能搞定的&#xff…

基于智能算法的无人机路径规划研究(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

Docker学习(4)—— 容器数据卷

数据卷是为了实现数据的持久化&#xff0c;完全独立于容器的生存周期&#xff0c;因此Docker不会在删除容器时删除其挂载的数据卷。 通过下述方式运行一个容器&#xff0c;会自动将docker容器内的数据保存进宿主机的磁盘中 docker run -it --privilegedtrue -v /宿主机绝对路…

都说自动化测试才是测试人员的新出路,为什么要做自动化测试?

一、自动化测试 自动化测试是把以人为驱动的测试行为转化为机器执行的一种过程。    个人认为&#xff0c;只要能服务于测试工作&#xff0c;能够帮助我们提升工作效率的&#xff0c;不管是所谓的自动化工具&#xff0c;还是简单的SQL 脚本、批处理脚本&#xff0c;还是自己…