Qt 中的XML
XML的基本介绍:
在前端开发中:HTML是用来显示数据,而XML是用来传输和存储数据的
- XML 指可扩展标记语言(EXtensible Markup Language)
- XML 是一种标记语言,很类似 HTML
- XML 的设计宗旨是传输数据,而非显示数据
- XML 标签没有被预定义。您需要自行定义标签。
- XML 被设计为具有自我描述性。
- XML 是 W3C 的推荐标准
XML 应用于 web 开发的许多方面,常用于简化数据的存储和共享。
- 通过 XML,可以在不兼容的系统之间轻松地交换数据。
- XML 独立于硬件、软件以及应用程序,XML 使您的数据更可用,也更有用。
- XML 数据以文本格式存储。这使得 XML 在不损失数据的情况下,更容易扩展或升级到新的操作系统、新应用程序或新的浏览器
在Qt中的XML:
使用Qt XML模块来对XML文档进行处理
- 使用DOM方法对XML文档进行读/写
- SAX方法对XML进行存取(这种方法已经过时)
- 从Qt5开始,使用Qt Core中的QXmlStreamReader和QXmlStreamWriter,使用流的方式对XML文档进行读写。
XML文件的介绍:
<? xml version="1.0" encoding="UTF-8"?>//XML说明,version版本号,encoding版本号
<root>//根元素<id id="1">//元素 元素属性<name>王老五</name>//元素 内容</id><id id="2"><name>张老四</name></id>
</root>//结束
xml的一些内容:
- 基本格式:<xxx>内容</xxx>
- XML有且仅有一个根元素 root
- 元素: root id name
- 属性格式: <元素 元素=”属性“>
- 内容:<元素>text</元素>
DOM中XML的表示:
| XML说明 | QDomProcessingInstruction |
| XML元素 | QDomElement |
| XML 属性 | QDomAttr |
| XML 内容 | QDomText |
| 全部同一使用 | QDomNode |
QDomNode
| isProcessingInstruction() | 判断是否为xml说明 |
| isElement() | 判断是否为xml元素 |
| isAttr() | 判断是否为xml属性 |
| isText() | 判断是否为xml内容 |
| toProcessingInstruction() | 转化为xml说明 |
| toElement() | 转化为xml元素 |
| toAttr() | 转化为xml属性 |
| toText() | 转化为xml内容 |
QDomDocument(Dom文档类)
使用QDomDocument表示整个XML文档,提供对文档数据的主要访问。
使用时需要在pro文件中添加:
QT += xml
常用的函数:
| toString(int indent=1) | 将分析的文档转换为文本的形式表示,1为缩进 |
| toByteArray(int indent=1) | 将分析的文档转换回其文本表示形式,1为缩进 |
| setContent() | 此函数从字节数组数据分析 XML 文档,并将其设置为文档的内容。它尝试按照 XML 规范的要求检测文档的编码。 |
| importNode() | 将节点导入节点从另一个文档导入到此文档。importedNode 保留在原始文档中;此函数创建可在此文档中使用的副本。 |
| elementsByTagName() | 返回一个QDomNodeList,其中包含文档中具有名称标记名的所有元素。节点列表的顺序是它们在元素树的预序遍历中遇到的顺序。 |
| elementById(QString id) | 返回根id匹配的元素 |
| documentElement() | 返回文档的根元素 |
| doctype() | 返回此文档的文档类型 |
| createTextNode() | 为可以插入到文档树中的字符串值创建一个文本节点 |
| createProcessingInstruction() | 创建一个可以插入到文档中的新处理指令 |
| createEntityReference(name) | 创建一个名为 name 的新实体引用,可以插入到文档中 |
| createElementNS() | 创建一个具有命名空间支持的新元素,该元素可以插入到 DOM 树中。 |
| createElemrnt(tagname) | 创建一个名为 tagName 的新元素,可以插入到 DOM 树中 |
| createComment() | 为可以插入到文档中的字符串值创建一个新注释 |
| createAttributeNS() | 创建具有命名空间支持的新属性,该属性可以插入到元素中。 |
| createAttribute(name) | 创建一个名为 name 的新属性,该属性可以插入到元素中 |
使用QDomDocument 读取xml中的数据:
- 创建一个QDomDocument对象
- 使用QFIle 打开xml文档
- 使用QDomDocument::setContent(file)把文件中的内容导入QDomDocument
- 使用QDocNode获取内容
首先创建一个xml文件,后缀为 .xml,然后把该文件添加到项目的资源文件中:

xml文件中添加以下代码:
<?xml version="1.0" encoding="UTF-8"?>
<root><id id="1"><name>wanglaowu</name></id><id id="2"><name>zhanglaosi</name></id>
</root>
在main函数中添加以下代码:
#include <QApplication>
#include<QDomDocument>
#include<QMessageBox>
#include<QFile>
#include<QDebug>
int main(int argc, char *argv[])
{QApplication a(argc, argv);QDomDocument domdoc("myDom");//创建一个Dom文档对象QFile file(":/new/prefix1/XMLtext.xml");if(!file.open(QFile::ReadOnly)){QMessageBox::information(0,"提示信息","xml文件打开失败",QMessageBox::Ok);return 0;}if(!domdoc.setContent(&file))//读取文件内容到domdoc{file.close();return 0;}file.close();//读取完关闭文件QDomNode firstNode=domdoc.firstChild();//获取第一个元素,XML说明qDebug()<<qPrintable(firstNode.nodeName())//输出版本号<<qPrintable(firstNode.nodeValue());//输出编码类型return a.exec();
}
对于qPrintable的解释:
const char *qPrintable(const QString &str)
相当于:将 str 作为 .这相当于 str.toLocal8Bit().constData()

输出xml中的全部内容:
可以把XML看作一棵树:

QDomElement docElem=domdoc.documentElement();//获取根元素QDomNode n=docElem.firstChild();//获取第一个子节点while(!n.isNull())//不为空的话{if(n.isElement())//如果是元素的话{QDomElement e=n.toElement();//获取该元素qDebug()<<qPrintable(e.tagName())//获取元素标记<<qPrintable(e.attribute("id"));//id属性的值QDomNodeList list=e.childNodes();//获取e的全部子节点for(int i=0;i<list.count();i++)//遍历列表{QDomNode node=list.at(i);if(node.isElement()){qDebug()<<" "<<qPrintable(node.toElement().tagName())//输出元素名<<qPrintable(node.toElement().text());//输出内容}}}n=n.nextSibling();//转到下一个兄弟节点}

创建一个XML文件并添加内容:
构建思路:

代码:
QDomDocument doc;//创建一个Dom对象QDomProcessingInstruction instruction;//XML说明instruction=doc.createProcessingInstruction("xml","version=\"1.0\" encoding=\"UTF-8\"");//创建XML说明doc.appendChild(instruction);//添加XML说明//创建根元素QDomElement root=doc.createElement("学生信息");doc.appendChild(root);//添加根元素//创建学生信息QDomElement id=doc.createElement("学号");QDomAttr number=doc.createAttribute("学号");//属性QDomElement name=doc.createElement("姓名");QDomElement age=doc.createElement("年龄");QDomElement height=doc.createElement("身高");QDomElement weight=doc.createElement("体重");QDomText text;//内容number.setValue(QString("1"));//设置学号的值id.setAttributeNode(number);//id元素中添加number属性//添加学生信息text=doc.createTextNode("王一");name.appendChild(text);text=doc.createTextNode("15");age.appendChild(text);text=doc.createTextNode("160");height.appendChild(text);text=doc.createTextNode("40");weight.appendChild(text);//把这些信息添加到id元素中id.appendChild(name);id.appendChild(age);id.appendChild(height);id.appendChild(weight);//将id添加到根元素中root.appendChild(id);//第二个学生id=doc.createElement("学号");number=doc.createAttribute("学号");//属性name=doc.createElement("姓名");age=doc.createElement("年龄");height=doc.createElement("身高");weight=doc.createElement("体重");number.setValue(QString("2"));//设置学号id.setAttributeNode(number);//id元素中设置number属性//添加信息text=doc.createTextNode("张三");name.appendChild(text);text=doc.createTextNode("16");age.appendChild(text);text=doc.createTextNode("165");height.appendChild(text);text=doc.createTextNode("45");weight.appendChild(text);//把这些信息添加到学号中id.appendChild(name);id.appendChild(age);id.appendChild(height);id.appendChild(weight);//将id添加到根元素中root.appendChild(id);QFile file("my.xml");if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))return;QTextStream out(&file);doc.save(out,4);//保存到out中,4格缩进file.close();
打开该文件:

查找、修改、删除操作:


void Widget::find_updata_delete(const QString S)//
{QFile file("my.xml");//打开该文件if(!file.open(QFile::ReadOnly)){return;//打开失败的话退出}QDomDocument doc;if(!doc.setContent(&file))//获取数据失败{file.close();return;}//获取成功的话QDomNodeList list=doc.elementsByTagName("学号");//获取标签for(int i=0;i<list.count();i++)//遍历这些标签{QDomElement e=list.at(i).toElement();//获取元素if(e.attribute("学号")==ui->lineEdit->text())//如果匹配成功的话{if(S=="delete")//删除操作的话{QDomElement root=doc.documentElement();//获取根节点root.removeChild(list.at(i));//根节点中删除QFile file("my.xml");if(file.open(QIODevice::WriteOnly|QIODevice::Truncate))return;QTextStream out(&file);doc.save(out,4);//保存到文件中file.close();//关闭文件}else if(S=="updata"){QDomNodeList child=list.at(i).childNodes();//获取当前节点所有的子节点child.at(0).toElement().firstChild().setNodeValue(ui->lineEdit_2->text());//更新姓名child.at(1).toElement().firstChild().setNodeValue(ui->lineEdit_3->text());//更新年龄child.at(2).toElement().firstChild().setNodeValue(ui->lineEdit_4->text());//更新身高child.at(3).toElement().firstChild().setNodeValue(ui->lineEdit_5->text());//更新体重QFile file("my.xml");if(file.open(QIODevice::WriteOnly|QIODevice::Truncate))return;QTextStream out(&file);doc.save(out,4);//保存到文件中file.close();//关闭文件}else if(S=="find"){qDebug()<<e.tagName()<<" "<<e.attribute("学号");//输出元素名和学号QDomNodeList nodeList=e.childNodes();//获取内容节点for(int i=0;i<nodeList.count();i++){QDomNode node=nodeList.at(i);if(node.isElement()){qDebug()<<node.toElement().tagName()<<" "<<node.toElement().text();//输出元素名和内容}}}}}
}
void Widget::on_pushButton_clicked()//查找
{find_updata_delete("find");
}
运行结果:

以上是Dom简单使用xml的方法。(感觉有点繁琐)
XML流
从Qt 4.3开始引入两个新类来读取和写入XML文档:
QXmlStreamReader类:
- 是一个快速的解析器,使用简单的流API来读取格式良好的XML文档
- QXmlStreamReader可以从QIODevice或QByteArray中读取数据
- 流读取器:将XML文档报告为一个记号流,使用程序代码自身来驱动循环,在需要的时候可以从读取器中一个接着一个地拉出记号,使用readNext()函数获取记号
QXmlStreamReader::TokenType:
| 常量 | 描述 |
| QXmlStreamReader::NoToken | 没有读过任何东西。 |
| QXmlStreamReader::Invalid | 使用error()和errorString()中报告错误 |
| QXmlStreamReader::StartDocument | 在documentVersion()中报告XML版本号,使用documentEncoding()中指定文档的编码 |
| QXmlStreamReader::EndDocument | 报告文档结束 |
| QXmlStreamReader::StartElement | 使用namespaceUri()和name()来报告元素开始,可以使用attributes()来获取属性 |
| QXmlStreamReader::EndElement | 使用nameSpaceUri()和name()来报告元素结束 |
| QXmlStreamReader::Characters | 使用text()来报告字符,如果字符是空白,那么isWhitespace()返回true,如果字符源于CDATA部分,那么isCDATA()返回true |
| QXmlStreamReader::Comment | 使用在text()中报告注释 |
| QXmlStreamReader::DTD | 使用在 text() 中报告 DTD,在 notationDeclDeclarations() 中报告表示法声明,在 entityDeclarations() 中报告实体声明。DTD 声明的详细信息在 dtdName()、dtdPublicid和dtdSystemid() 中报告 |
| QXmlStreamReader::EntityReference | 报告无法解析的实体引用。引用的名称在 name() 中报告,替换文本在 text() 中报告。 |
| QXmlStreamReader::ProcessingInstruction | 使用processingInstruction Target()和processingInstruction Data()中报告处理指令 |
使用QXmlStreamReader读取xml文档:
具体流程:
- 先打开文件 file
- 创建一个阅读器,使用setDevice()设置读取对象
- 使用readNext()读取一个记号
- 使用读取的记号进行判断
#include <QApplication>
#include<QXmlStreamReader>
#include<QFile>
#include<QDebug>
int main(int argc, char *argv[])
{QApplication a(argc, argv);QFile file(":/new/xml/my.xml");if(!file.open(QIODevice::ReadOnly|QIODevice::Text)){return 0;}QXmlStreamReader reader;//创建一个阅读器reader.setDevice(&file);//设置需要读取的文件while(!reader.atEnd())//如果不到结尾{QXmlStreamReader::TokenType type=reader.readNext();//获取一个记号if(type==QXmlStreamReader::StartDocument)//读取XML说明{qDebug()<<reader.documentVersion()<<" "<<reader.documentEncoding();//读取版本号和编码类型}if(type==QXmlStreamReader::StartElement)//获取元素{qDebug()<<reader.name();//获取元素名if(reader.attributes().hasAttribute("id"))//如果有属性{qDebug()<<reader.attributes().value("id");//输出属性}}if(type==QXmlStreamReader::EndElement)//获取结束元素{qDebug()<<reader.name();}if(type==QXmlStreamReader::Characters&&!reader.isWhitespace()){qDebug()<<reader.text();//读取内容}}if(reader.hasError()){qDebug()<<"error:"<<reader.errorString();}file.close();//关闭文件return a.exec();
}
QXMLStreamWriter
用于编写XML文档
常用函数:
| setAutoFormatting() | 设置自动化类型 |
| hasError() | 写入失败返回true |
| setCodec() | 设置解码器,默认使用UTF-8 |
| setDevice() | 设置写入的设备 |
| writeTextElement() | 写入带有内容的元素 |
| writeStartElement() | 写入起始元素 |
| writeStartDocument() | 写入XML版本号和编码信息 |
| writeProcessingInstruction() | 编写包含目标和数据 XML 处理指令 |
| writeNamespace() | 为带有前缀的命名空间 Uri 编写命名空间声明 |
| writeEndElement() | 关闭上一个开始元素 |
| writeEndDocument() | 关闭所有剩余的打开开始元素并写入换行符 |
| writeEmptyElement() | 写入一个带有名称的空元素 |
| writeDTD() | 写入 DTD 节 |
| writeAttributes() | 写入属性 |
例子:
QFile file("Myxml.xml");if(!file.open(QIODevice::WriteOnly|QIODevice::Text)){return 0;}QXmlStreamWriter Writer;Writer.setDevice(&file);//获取流Writer.setAutoFormatting(true);Writer.writeStartDocument();//添加XML说明(版本号和编码信息Writer.writeStartElement("student");//写入起始元素Writer.writeStartElement("id");Writer.writeAttribute("id","1");//写入属性Writer.writeTextElement("name","王维");Writer.writeTextElement("age","15");Writer.writeTextElement("height","165");Writer.writeTextElement("weight","50");Writer.writeEndElement();//结束id元素编辑Writer.writeEndElement();//结束student元素编辑Writer.writeEndDocument();//结束整个的编辑file.close();//关闭文件
参考文档:
XML 的用途 (w3school.com.cn)
XML Processing | Qt XML 5.15.12
相关文章:
Qt 中的XML
XML的基本介绍: 在前端开发中:HTML是用来显示数据,而XML是用来传输和存储数据的 XML 指可扩展标记语言(EXtensible Markup Language)XML 是一种标记语言,很类似 HTMLXML 的设计宗旨是传输数据,而…...
网络应用之URL
URL学习目标能够知道URL的组成部分1. URL的概念URL的英文全拼是(Uniform Resoure Locator),表达的意思是统一资源定位符,通俗理解就是网络资源地址,也就是我们常说的网址。2. URL的组成URL的样子:https://news.163.com/18/1122/10/E178J2O4000189FH.html…...
【Linux】重定向原理dup2缓冲区
文章目录重定向原理输出重定向关于FILE解释输出重定向原理追加重定向输入重定向dup2缓冲区语言级别的缓冲区内核缓冲区重定向原理 重定向的本质就是修改文件描述符下标对应的struct file*的内容 输出重定向 输出重定向就是把本来应该输出到显示器的数据重定向输出到另一个文…...
ROG配置ubuntu20.04.5双系统要点
win11ubuntu20.04.5 1. BIOS设置 开机长按F2进入bios设置,修改advanced参数: boot -> 关闭fast bootsecurity -> 关闭secure boot设置VMD controller为Disabled(其他电脑是修改硬盘的SATA和ACHI模式)。但是改了之后windo…...
机械革命旷世G16电脑开机变成绿屏了无法使用怎么办?
机械革命旷世G16电脑开机变成绿屏了无法使用怎么办?最近有用户使用的机械革命旷世G16电脑一开机之后,电脑屏幕就变成了绿色的,无法进行任何的操作。出现这个问题可能是因为电脑中病毒了,或者是系统出现故障。我们可以通过U盘来重新…...
python中关于time模块的讲解---指定格式时间字符串转为时间戳
本文章可以解决任意字符串格式时间转为时间戳 返回json格式 可以在此基础上进行修改 时间格式控制符 说明 %Y 四位数的年份,取值范围为0001~9999,如1900 %m 月份(01~12),例如10 %d 月中的一天(01~31)例…...
MySql存储引擎与索引
MySql引擎 存储引擎是具体操作数据的地方,是一种对数据存储的技术与其配套的功能 不同存储引擎所采用存储的方式的不同,并且索引技巧与锁定水平也不同 根据业务的需求灵活的选择存储引擎即可满足的实际的需要 Innodb Innodb是MySql中的默认安装的引擎…...
typing库
typing 库 引入 在日常代码编写中,由于python语言特性,不用像go等编译性语言一样,在定义函数时就规范参数和放回值的类型。 def demo(a, b):return "ab" 此时 a 和 b 可以传入任意类型参数毫无疑问,这一特性&#…...
linux shell 入门学习笔记10内置shell命令
bash基础的内置命令 echoevalexecexportreadshift echo命令 -n 不换行输出 -e 解析字符串中的特殊符号\n 换行 \r 回车 \t 制表符 四个空格 \b 退格-n参数演示 xiao123xiao123:~/Downloads$ echo 你真胖;echo 你还挺可爱; 你真胖 你还挺可爱 xiao123xiao123:~/Downloads$ ec…...
[动手写操作系统]-02-开机运行系统并打印‘hello‘
文章目录 理解三个概念: 中断interrupts, CPU,寄存器registers 目标:让上一个静默的界面打印一些文本 我们将改进我们的无限循环引导扇区并在屏幕上打印一些东西。我们将为此提出中断。 我们尝试将"Hello"写到寄存器al, 字节0x0e写到ah (the higher part of ax),并…...
Delete `␍`eslint(prettier/prettier) in vscode 的解决方案
错误描述从 Github 仓库拉取代码,使用 vscode 打开,页面报错,每一行都爆红 (如下图)问题原因由于历史原因,windows下和linux下的文本文件的换行符不一致。Windows在换行的时候,使用了换行符CRLF…...
gof23 设计模式 各个模式代码demo
Gof23 设计模式,也叫Gang of Four(GoF)设计模式,是由四位设计模式大师(Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides)撰写的一本书——《设计模式:可复用面向对象软件的基础》所…...
0 初识Kotlin
0 基本介绍 相信很多开发者对Kotlin还是比较陌生的。 Kotlin是一种新型的编程语言,由JetBrains公司开发与设计,在2012年开源, 但没引起什么注意。 直到2017年google宣布将Kotlin作为Android开发的首选语言,Kotlin才开始大放异彩。…...
阿里云服务器部署SpringBoot+Vue项目(宝塔面板傻瓜式操作)
准备工作 一台服务器(我用的是阿里云)SpringBoot项目的jar包Vue项目的dist包 一、购买服务器 然后重置实例密码。 远程连接 登陆成功后安装宝塔面板 二、安装宝塔面板(无账号的注册一个账号) 地址:https://www.bt.cn/new/download.html 选择对应的镜像、不知道…...
27. 移除元素 26. 删除有序数组中的重复项 88. 合并两个有序数组(双指针遍历)
目录[27. 移除元素-力扣](https://leetcode.cn/problems/remove-element/description/?languageTagsc)[26. 删除有序数组中的重复项](https://leetcode.cn/problems/remove-duplicates-from-sorted-array/)[88. 合并两个有序数组](https://leetcode.cn/problems/merge-sorted-…...
什么时候用std::move()?
文章目录1. "是什么?"2. "有何用?"3. "什么时候用?"1. “是什么?” 虽然 std::move() 从技术角度上是一个函数 ,但我认为它不是真正的函数。 它是编译器考虑表达式值的方式之间的转换器。 2. “有何用?” 首先要注意的是 std…...
建立做机器学习项目的范式
建立起做机器学习项目的范式,萃取出核心步骤,避免后面做项目没有明确的方向。 核心步骤: 1、明确自己想做什么样的项目,感兴趣的领域; 2、找到满足项目的数据集,开源的或者自建数据集; 数据…...
搭建k8s高可用集群—20230225
文章目录多master(高可用)介绍高可用集群使用技术介绍搭建高可用k8s集群步骤1. 准备环境-系统初始化2. 在所有master节点上部署keepalived3.1 安装相关包3.2 配置master节点3.3 部署haproxy错误解决3. 所有节点安装Docker/kubeadm/kubelet4. 部署Kuberne…...
Java 修饰符和多态
文章目录一、修饰符1. 权限修饰符2. 状态修饰符2.1 final2.2 static二、多态1. 成员访问特点2. 多态中的转型3. 多态案例一、修饰符 1. 权限修饰符 2. 状态修饰符 2.1 final final 关键字是最终的意思,可以修饰成员方法、成员变量及类。 //1.修饰成员变量 publi…...
学了一年Java的我,想转嵌入式了
秋名山码民的主页 🎉欢迎关注🔎点赞👍收藏⭐️留言📝 🙏作者水平有限,如发现错误,还请私信或者评论区留言! 目录前言为啥我想去转行?如果我现在选择转硬件,我…...
《Windows Sysinternals实战指南》PsTools 学习笔记(7.10):PsFile——远程“谁在占用这个文件/共享”的取证与解占用
🔥个人主页:杨利杰YJlio❄️个人专栏:《Sysinternals实战教程》《Windows PowerShell 实战》《WINDOWS教程》《IOS教程》《微信助手》《锤子助手》 《Python》 《Kali Linux》 《那些年未解决的Windows疑难杂症》🌟 让复杂的事情更…...
别再死记硬背了!用C++邻接矩阵手搓Dijkstra算法,我连路径打印都给你讲明白了
从零实现Dijkstra算法:邻接矩阵实战与路径回溯详解 在计算机科学的世界里,寻找两点之间最短路径的问题就像现代都市中的导航系统——我们需要在错综复杂的道路网络中找到最优解。Dijkstra算法作为解决单源最短路径问题的经典方法,其重要性不…...
三个00后给母校捐了“20亿”,全网炸了——结果这20亿可能就值几百块?
整件事最魔幻的地方在于:你第一眼看到“20亿”,脑子里自动补上的单位是“人民币”。然后一算账,发现可能连捐的那个展示牌都不如。这事到底是怎么回事?前几天,郑州西亚斯学院搞了一场挺隆重的捐赠仪式。三个00后校友—…...
数字体育可视化 | 智慧赛事与场馆全域协同管控
在发展新质生产力的时代背景下,我国智慧体育行业迎来全新发展机遇与时代使命,进入高速蓬勃发展的新阶段。作为智慧体育生态的核心单元,数字体育通过新一代信息技术与体育产业的深度融合,覆盖群众体育、竞技体育、赛事运营、体育产…...
BarTender如何在线刷新许可证
1、在BarTender服务端打开Administration Console注意:此操作需要服务端连接外网,登录本地管理员账户2、点击许可并等待右侧弹出许可证界面选中需要操作的许可证并点击右侧刷新按钮3、许可证刷新成功4、刷新完成后观察刷新后的许可证前方是否有感叹号如果…...
基于以太网转换器的工业交换机接入方案提升数据传输效率与稳定性
一、项目背景 某中型自动化生产企业现有3条生产线,核心控制设备采用10套西门子S7-200 SMART CPU SR40 PLC,负责生产线配料、输送、检测等全流程控制。随着企业数字化升级推进,需实现PLC与上位机、触摸屏的数据实时交互,接入工厂简…...
2026年多Agent协作实战:用CrewAI搭建5角色AI开发团队
前言上一篇我们学习了MCP协议,掌握了AI与工具交互的标准化方法。本文将更进一步,探讨如何让多个AI Agent协同工作——就像组建一个AI开发团队,每个Agent负责不同的角色,通过协作完成复杂任务。—## 一、为什么需要多Agent协作&…...
瑞芯微RK3568与RK3399深度对比:选型指南与实战解析
1. 项目概述:一次关于“芯”的深度对话 最近在选型嵌入式开发板时,很多朋友,尤其是刚入行或准备从传统方案转向国产平台的朋友,都会在瑞芯微的RK3568和RK3399这两颗明星处理器之间纠结。手头正好有迅为基于这两颗芯片的开发板&…...
3步打造高效macOS菜单栏:Hidden Bar深度使用指南
3步打造高效macOS菜单栏:Hidden Bar深度使用指南 【免费下载链接】hidden An ultra-light MacOS utility that helps hide menu bar icons 项目地址: https://gitcode.com/gh_mirrors/hi/hidden 作为macOS用户,你是否曾为菜单栏图标拥挤不堪而烦恼…...
15天学会AI应用开发(一)搭建AI大模型应用开发环境
AI大模型时代来了,程序员们纷纷入坑AI应用开发,可是苦于AI教程良莠不齐,往往花费了大量时间精力和金钱,却仍然过其门而不入。 有鉴于此,博主开始连载AI应用开发教程《15天学会AI应用开发》,帮助大家快速掌…...
