批处理 for应用 |
作者:未知 时间:2005-09-13 21:50 出处:Blog.ChinaUnix.net 责编:chinaitpower |
摘要:批处理 for应用 |
for命令应用 |
Powered by ScribeFire.
我的工作,也就是我的生活~~~
批处理 for应用 |
作者:未知 时间:2005-09-13 21:50 出处:Blog.ChinaUnix.net 责编:chinaitpower |
摘要:批处理 for应用 |
for命令应用 |
Powered by ScribeFire.
NetBeans 5.5™ UML 建模模块为 NetBeans IDE 提供了 UML 建模功能。通过 UML 建模功能,分析师和设计人员可以使用一种标准的建模语言来设计应用程序;开发者则可以根据 UML 模型来生成源代码,并通过对源代码执行的更改来更新此模型。
您可以通过 NetBeans 更新中心下载并安装 UML 建模模块。要访问更新中心,请在 NetBeans IDE 主菜单中单击“工具”>“更新中心”。
Mac 用户请注意:Macintosh OS X 平台目前不支持 UML 建模模块。要获取有关已知问题和解决方法的更多信息,请参见适用于 Mac OS 平台的发行说明。
目录
本主题指定了在开始安装 NetBeans 5.5 UML 建模模块之前,必须满足的先决条件。
所需的软件
在试图安装 NetBeans 5.5 UML 建模模块之前,必须首先安装以下软件:
注意:有关安装 NetBeans 5.5 UML 建模模块的系统要求信息,请参见 UML 建模模块发行说明。
- NetBeans IDE 5.5(以下简称 "IDE")
本部分包含有关下载 NetBeans 5.5 UML 建模模块并在所有支持的平台上进行安装的说明。
注意:如果曾经安装了任何 UML 建模模块的 Beta 版本,则无需卸载 Beta 版本。不过,这会造成安装后期的步骤略有不同,我们将在下面的步骤中加以说明。
注意:如果通过 UML 建模模块的 Beta 版本进行升级,则系统不会提示您接受 4 个 UML 许可证。
在 IDE 中处理 UML 项目时,应增加 NetBeans 的缺省内存设置。安装了 UML 模块后,请执行以下步骤以确保在处理 UML 项目时 IDE 中的内存设置正确无误。
C:\Program Files\netbeans-5.5
(Microsoft Windows)。etc/
目录。netbeans.conf
文件。netbeans_default_options
行中,将 -J-Xmx128m
命令行开关选项更改为 -J-Xmx512m
。linux网卡模块:mii.o,再是insmod具体的驱动模块。
vsftpd:使用xined 做demon无法绑定21端口,为使vsftpd独立监听启动,改xined.d/vsftpd中的disable为yes。vsftpd.conf中设为listen=YES,ipv6补丁
重定向:0标准输入、1标准输出、2标准错误、&全部。例如,ls -a 2 >filename 错误信息。
mencoder编解码:mencoder -ovc format -oav format sourcefile -o dest。
sql:1st范式:不存在两行完全相同;2nd:部分依赖于主键不存在,如果有则分成多个表;3rd:消除传递依赖。
sourceinsight的解析*.cc问题:preference中C++language->doc type->加入*.cc->重解析
ipv6suite 使用:cmakelist.txt,omnet.ini,*.ned,*.xml,将*.ned加入../../etc/default.ini中可以不 用preload;xmllint --noout --valid *.xml判断xml的正确性至无输出。移动节点xml需要定义mn.linklayer[0].NWIName="wireless Ethermodule";优化DAD、HMIPv6也在这里配置。udp流numofUdpApps配置数量,Udpname,server见 pingnetwork,路由时的下跳是sitelocal地址。看MN的网络层信息: *.MN.networkLayer.proc.forwarding.core.routingInfoDisplay = true
如果网速过慢,客户端两次发送的数据可能会被服务端一次就全部接收。
那么这种情况下要如何分清服务端接收到的数据包是客户端几次发送的呢!
有一种方法是给每次发送的数据包加上数据包的长度,可是这仲做法如果网上出现丢包怎么办呀! 问题点数:0、回复次数:19Top
http://www.xiaozhou.net/ReadNews.asp?NewsID=240Top
一般来说,TCP的可靠性是应该充分相信的。Top
我想用下面的方法实现分包
每一个数据包在发送时定义如下格式
数据包长度|数据包序号|数据包内容
可是上面的形式在一定的情况下是错误的
就是如果在客户端一份数据被自动分成两个数据包发送,而且第二个数据包在途中丢失,那么数据就不能完整的到达服务端了。
大家谁有TCP报头的数据格式资料啊!Top
只要协议定义得好,粘包就好解决
一般来说协议中都应该包含包头和数据长度Top
自己定义一个协议头,协议头的长度是固定的,协议头包含数据内容的长度。
接收消息时,先接收固定长度的协议头,然后根据协议头中数据的长度再接收数据内容。
也就是说,一条消息分2次接收。
这样可以处理粘包问题的。Top
是的,这样的情况你必须定义你的数据包的格式,包头-信息类别-长度等,必要时需要加校验位和结束字符.
但是TCP报文是可靠的.Top
通过自定义帧格式来完成,在帧中加入长度字段Top
同意 karllere ,不过序号不需要,因为 TCP 不会乱序Top
请看下面的这两组数据
报头 | 报文
10 ABCDEFGHIJ
8 ABCDEFGH
假设以上报文的第一组被操作系统分成两次发送
第一次为 10ABCD
第二次为 EFGHIJ
如果第二次的数据丢失,下一组数据8ABCDEFGH又到达了。
那么在缓冲区中就会有这样的形式10ABCD8ABCDEFGH
根据数据格式定义,在一次读取数据时就会取出10ABCD8ABCDE
如果出现以上情况的话就会造成所有后续发来的数据包全部读取错误。
Top
MFC中的CSocket类内部会自动处理粘包和丢包的问题吗?Top
tcp的协议层给你处理了丢包,所以你都不需要考虑丢包的问题。
你把收到的数据放倒一个buffer里,从里面找header,然后解析出数据就ok了。
如果udp的话会乱序,tcp都不需要考虑这些的。Top
可以使用如下的方法接收数据:
需要循环调用Receive的 知道你实际接收的字节数== 你本来打算接收的字节数
下面是我的程序中的一段代码
BOOL MyReceiveData(CSocket *psocket,char *data,DWORD len)
{
DWORD left,idx,ret;
left=len;
idx=0;
while(left>0)
{
ret = psocket->Receive(&data[idx],left,0 );
if( ret == SOCKET_ERROR)
{
return FALSE;
}
left-=ret;
idx+=ret;
}
return (idx==len)?TRUE:FALSE;
}Top
老问题,这东西还是使用自己定义的协议。
说明你的数据包的大小。
使用那个socket的控件就爽多了。
Top
CSocketFile 是完成什么优化工作的呢!
在MFC的示例中总是说要将CSocket、CSocketFile和CArchive联合使用来完成信息的收发工作。
可是我感觉这样还不如真接用CAsyncSocket::Receive方便呢!
我就在想...
CSocketFile是不是内部有处理粘包的机制啊!
还有就是对于Socket的一切猜想都需要一个
能不能给我提供一个呀!Top
MFC的CSocketFile有毛病的,千万别用。在粘包时经常出问题,最后我放弃用它,就好了。
用CAsyncSocket::Receive接收下来以后,自己处理吧。Top
Oracle 10g rac 始支持两个instance的failover和loadbalance。示例如下:
VMRACTEST.HF.COM=
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP) (HOST = 172.16.209.47) (PORT = 1521))
(ADDRESS = (PROTOCOL = TCP) (HOST = 172.16.209.49) (PORT = 1521))
(LOAD_BALANCE = yes)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = vmractest.hf.com)
(FAILOVER_MODE =
(TYPE = SELECT)
(METHOD = BASIC)
(RETRIES = 180)
(DELAY = 5))
)
)
如上配置,若使用oci client连接RAC则client将连接到172.16.209.47 或 172.16.209.49的任意一台实例上,假设我们连到了49上。TCP Connection状态为ESTABLISHED。当49的instance发生故障,该client端TCP连接状态变为Close_WAIT,不要 以为连接已断。当我们执行数据库操作时,oci将重连到47的TCP Connection
这两天碰到一个TCP read buffer 满,而发送Zero window message 给Server, Server 在收到多次这样的message后断开该缓慢连接的问题。想到了几个问题,查证后特记录如下:
1. TCP Zero Window message 与 RST ACK:Zero Window message 通常在本地recieve buffer 满时发出,向server通知"已经不能再向我发数据了,已经处理不过来了",server收到这样的notify则会暂停向该client发数据。长此 以往,有些防火墙的规则会发RST message将这些慢连接干掉。
2. TCP MSS 与 MTU 分段:MSS叫Maxitum Segment Size ,通常的实现就是按照MTU来的,因此MSS一般来说大小为1500-20-20=1460。如果应用层数据太大,大于一个MSS,则TCP将作分段处 理。MTU基于物理层而言,ethnet的MTU为1500,PPPoe为1492,上层的message大小如果大于MTU,则将在IP层被分片。有的 TCP报文为保证顺序要求,设置了Dont fragment 位,指示IP层不要分片,如果这段网络上的MTU <>
3. 阻塞和非阻塞套接字,阻塞套接字会将所有的data拷贝到发送缓冲区后才返回,也就是如果窗口为16K,要发送32k的数据返回时,至少有16K的数据已 经到达对端,还有部分数据在本地缓冲区内。如果为非阻塞模式,发送32K数据将马上返回,返回的nbyte小于32K,需要通过循环将所有数据发完。
void MainWindow::closeEvent(QCloseEvent *event)
{
if (maybeSave())
{
writeSettings();
event->accept();
}
else
{
event->ignore();
}
}
QString fileName = QFileDialog::getOpenFileName(this);
if (!fileName.isEmpty())
{
loadFile(fileName);
}
QString fileName = QFileDialog::getSaveFileName(this);
if (fileName.isEmpty())
{
return false;
}
newAct = new QAction(QIcon(":/images/new.png"), tr("&New"), this);
newAct->setShortcut(tr("Ctrl+N"));
newAct->setStatusTip(tr("Create a new file"));
connect(newAct, SIGNAL(triggered()), this, SLOT(newFile()));
openAct = new QAction(QIcon(":/images/open.png"), tr("&Open..."), this);
openAct->setShortcut(tr("Ctrl+O"));
openAct->setStatusTip(tr("Open an existing file"));
connect(openAct, SIGNAL(triggered()), this, SLOT(open()));
saveAct = new QAction(QIcon(":/images/save.png"), tr("&Save"), this);
saveAct->setShortcut(tr("Ctrl+S"));
saveAct->setStatusTip(tr("Save the document to disk"));
connect(saveAct, SIGNAL(triggered()), this, SLOT(save()));
saveAsAct = new QAction(tr("Save &As..."), this);
saveAsAct->setStatusTip(tr("Save the document under a new name"));
connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs()));
exitAct = new QAction(tr("E&xit"), this);
exitAct->setShortcut(tr("Ctrl+Q"));
exitAct->setStatusTip(tr("Exit the application"));
connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
cutAct = new QAction(QIcon(":/images/cut.png"), tr("Cu&t"), this);
cutAct->setShortcut(tr("Ctrl+X"));
cutAct->setStatusTip(tr("Cut the current selection's contents to the "
"clipboard"));
connect(cutAct, SIGNAL(triggered()), textEdit, SLOT(cut()));
copyAct = new QAction(QIcon(":/images/copy.png"), tr("&Copy"), this);
copyAct->setShortcut(tr("Ctrl+C"));
copyAct->setStatusTip(tr("Copy the current selection's contents to the "
"clipboard"));
connect(copyAct, SIGNAL(triggered()), textEdit, SLOT(copy()));
pasteAct = new QAction(QIcon(":/images/paste.png"), tr("&Paste"), this);
pasteAct->setShortcut(tr("Ctrl+V"));
pasteAct->setStatusTip(tr("Paste the clipboard's contents into the current "
"selection"));
connect(pasteAct, SIGNAL(triggered()), textEdit, SLOT(paste()));
aboutAct = new QAction(tr("&About"), this);
aboutAct->setStatusTip(tr("Show the application's About box"));
connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
aboutQtAct = new QAction(tr("About &Qt"), this);
aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
fileMenu = menuBar()->addMenu(tr("&File"));
fileMenu->addAction(newAct);
fileMenu->addAction(openAct);
fileMenu->addAction(saveAct);
fileMenu->addAction(saveAsAct);
fileMenu->addSeparator();
fileMenu->addAction(exitAct);
editMenu = menuBar()->addMenu(tr("&Edit"));
editMenu->addAction(cutAct);
editMenu->addAction(copyAct);
editMenu->addAction(pasteAct);
menuBar()->addSeparator();
helpMenu = menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(aboutAct);
helpMenu->addAction(aboutQtAct);
fileToolBar = addToolBar(tr("File"));
fileToolBar->addAction(newAct);
fileToolBar->addAction(openAct);
fileToolBar->addAction(saveAct);
editToolBar = addToolBar(tr("Edit"));
editToolBar->addAction(cutAct);
editToolBar->addAction(copyAct);
editToolBar->addAction(pasteAct);
QSettings settings("Trolltech", "Application Example");
QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
QSize size = settings.value("size", QSize(400, 400)).toSize();
QSettings settings("Trolltech", "Application Example");
settings.setValue("pos", pos());
settings.setValue("size", size());
int ret = QMessageBox::warning(this, tr("Application"),
tr("The document has been modified.\n"
"Do you want to save your changes?"),
QMessageBox::Yes | QMessageBox::Default,
QMessageBox::No,
QMessageBox::Cancel | QMessageBox::Escape);
if (ret == QMessageBox::Yes)
return save();
else if (ret == QMessageBox::Cancel)
return false;
cp src/translations/qt_untranslated.ts ./qt_zh_CN.ts
win32:CONFIG += console
./configure -static //一定要加static选项
gmake
gmake install
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForLocale(QTextCodec::codecForName("GBK"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GBK"));
QTextCodec::setCodecForTr(QTextCodec::codecForName("GBK"));
QMessageBox::information(NULL, "信息", "关于本软件的演示信息", QMessageBox::Ok, QMessageBox::NoButtons);
QApplication::addLibraryPath(strPluginsPath");
TEMPLATE=lib
LIBS += -Lyourdlllibpath -lyourdlllibname
class MyThread : public QThread
{
public:
void run();
};
void MyThread::run()
{
QProcess::execute("notepad.exe");
}
class ...............
{...........
MyThread thread;
............
};
.....................
thread.start();
void myMessageOutput( QtMsgType type, const char *msg )
{
switch ( type ) {
case QtDebugMsg:
//写入文件;
break;
case QtWarningMsg:
break;
case QtFatalMsg:
abort();
}
}
int main( int argc, char** argv )
{
QApplication app( argc, argv );
qInstallMsgHandler( myMessageOutput );
......
return app.exec();
}
images/copy.png
images/cut.png
images/new.png
images/open.png
images/paste.png
images/save.png
RESOURCES = res.qrc
...
:images/copy.png
...
裕作小记:
这几天在埋头写自己的3D文件浏览器(稍后发布),突发奇想的要把自己的内部格式转化成XML,于是,把以前在研究所时用过的ExPat翻了出来。 ExPat是基于事件的XML解释器,速度挺快的,但结构方面有点不敢恭维--当年写配置文件的导出导入部分花了我足足1个星期!而且由于它是基于事件发 生的次序(SAX),似乎有时会发生一些无法控制的情况--例如进入某Level后忘了记录,结果……后面的程序全部死掉!这时想起同事之前推荐的 TinyXML,结果……用了不到3小时就把我的3D格式导出来了~~呵呵。以下是一篇转贴的TinyXML基础,稍后我会写一篇TinyXML的实战例 子,敬请留意 :-)
PS:由于没找到正式的出处,所以把全文引用如下,并没有写上引用出处--如果哪位朋友知道,请告知在下。
-----------------------------------------------
TinyXml学习笔记
张弛
TinyXml是一个基于DOM模型的、非验证的轻量级C++解释器。
目前XML的解析主要有两大模型:SAX和DOM。
其中SAX是基于事件的,其基本工作流程是分析XML文档,当发现了一个新的元素时,产生一个对应事件,并调用相应的用户处理函数。这种方式占用内存少,速度快,但用户程序相应得会比较复杂。
而DOM(文档对象模型),则是在分析时,一次性的将整个XML文档进行分析,并在内存中形成对应的树结构,同时,向用户提供一系列的接口来访问和编辑该树结构。这种方式占用内存大,速度往往慢于SAX,但可以给用户提供一个面向对象的访问接口,对用户更为友好。
另据说,一些同时提供了SAX和DOM接口的库,是在底层先实现SAX,再在SAX的基础上实现DOM。
目前我知道的XML解析库有下面几个:
名称 | 访问接口 | 是否支持验证 | 备注 |
Expat | SAX/Local | 不清楚 | Local指它还有一套自己访问模型 |
LibXML2 | SAX/DOM | 是 | |
TinyXml | DOM | 否 | |
XML4C | SAX/DOM | 是 | 和Xerces-C是一家,不过用了ICU,国际化似乎更好 |
Xerces-C | SAX/DOM | 是 | |
XML Booster | Local | 不清楚 | 这个库不是特别了解,好像是类似yacc那样,可以生成一个特定的解析器,估计效率应该很高(看名字也像)。 |
对于一个特定的XML文档而言,其正确性分为两个层次。首先是其格式应该符合XML的基本格式要求,比如第一行要有声明,标签的嵌套层次必须前后一致等等,符合这些要求的文件,就是一个合格的XML文件,称作well-formatted。但除此之外,一个XML文档因其内容的不同还必须在语义上符合相应的标准,这些标准由相应的DTD文件或者Schema文件来定义,符合了这些定义要求的XML文件,称作valid。
因此,解析器也分为两种,一种是验证的,即会跟据XML文件中的声明,用相应的DTD文件对XML文件进行校验,检查它是否满足DTD文件的要求。另一种是忽略DTD文件,只要基本格式正确,就可以进行解析。
就我所知,验证的解析器通常都是比较重量级的。TinyXml不支持验证,但是体积很小,用在解析格式较为简单的XML文件,比如配置文件时,特别的合适。
TinyXml首页在http://www.grinninglizard.com/tinyxml/index.html,从这里可以找到最新版本的源代码,目前的版本是2.3.4。
TinyXml在构建时可以选择是否支持STL,选择的话,则可以使用std::string,所以通常应该打开这个选项。
在Windows上,TinyXml的源码包里提供了VC6的工程文件,直接用它就可以生成两个静态库(带STL和不带STL),非常容易。唯一需要注意的是,默认生成的库是单线程的,如果用在多线程的项目中,需要改动一下配置,生成相应的多线程库。
在Unix平台上,TinyXml的源码包里只提供了一个Makefile,对于典型的Linux系统,或装了gcc和gmake的其他Unix,这个Makefile足够用了,我在RH9和RHEL4上测试,简单的make就成功了。需要注意的有以下几点:默认的编译是不支持STL的,可以通过编辑Makefile的TINYXML_USE_STL := NO那一行,把NO改成YES就可以支持STL了;还有默认只生成了一个测试程序,没有生成任何库,如果要生成静态库的话,可以用ar命令,将生成的几个目标文件打包就行了,如果要生成动态库,则需要加上-fpic参数重新编译。
构建了相应的库之后,在使用了它们的工程中,只要在连接时把他们连上就行了。需要注意的是,如果需要STL支持,在编译用到了TinyXml的文件时,需要定义一个宏TIXML_USE_STL,对gcc,可以使用参数-DTIXML_USE_STL,对cl.exe(VC),可以使用参数/DTIXML_USE_STL,如果嫌麻烦,可以直接定义在 tinyxml.h文件里。
TinyXml实现的时DOM访问模型,因此提供了一系列的类对应XML文件中的各个节点。主要类间的关系如下图所示:
TiXmlBase:其他类的基类,是个抽象类
TiXmlNode:表示一个节点,包含节点的一般方法,如访问自节点、兄弟节点、编辑自身、编辑子节电
TiXmlDocument:表示整个XML文档,不对应其中某个特定的节点。
TiXmlElement:表示元素节点,可以包含子节点和TiXmlAttribute
TiXmlComment:表示注释
TiXmlDeclaration:表示声明
TiXmlText:表示文本节点
TiXmlUnknown:表示未知节点,通常是出错了
TiXmlAttribute:表示一个元素的属性
下面是一个简单的例子:
version="1.0" encoding="utf-8" ?>
<book>
<name>TinyXml How To
<description>Some words…
整个文档,对应TiXmlDocument
book,name,price, description,都对应TiXmlElement
第一行对应一个TiXmlDeclaration
第二行对应一个TiXmlComment
“TinyXml How To”对应一个TiXmlText
unit则是price的一个TiXmlAttribute
这些类与XML文件中的相应元素都有很好的对应关系,因此相信参照TinyXml的文档,可以很容易的掌握各个方法的使用。
各类之间的转换
由于各个节点类都从TiXmlNode继承,在使用时常常需要将TiXmlNode*类型的指针转换为其派生类的指针,在进行这种转换时,应该首先使用由TiXmlNode类提供的一系列转换函数,如ToElement(void),而不是c++的dynamic_cast
检查返回值
由于TinyXml是一个非校验的解析器,因此当解析一个文件时,很可能文件并不包含我们预期的某个节点,在这种情况下,TinyXml将返回空指针。因此,必须要对返回值进行检查,否则将很容易出现内存访问的错误。
如何重头建立一个XML文件
先建立一个TiXmlDocument对象,然后,载入某个模板,或者直接插入一个节点作为根节点,接着就可以像打开一个已有的XML文件那样对它进行操作了。
TinyXml最大的特点就是它很小,可以很方便的静态连接到程序里。对于像配置文件、简单的数据文件这类文件的解析,它很适合。但是由于它是非验证的,因此需要在程序里做许多检查工做,加重了程序编写的负担。因此对于复杂的XML文件,我觉得最好还是用验证的解析器来处理。
实战TinyXML
作者:裕作
(本文为原创,转贴请注明出处:http://blog.csdn.net/KyosukeNo1)
这几天在埋头写自己的3D文件浏览器(稍后发布),突发奇想的要把自己的内部格式转化成XML,于是,把以前在研究所时用过的ExPat翻了出来。 ExPat是基于事件的XML解释器,速度挺快的,但结构方面有点不敢恭维--当年写配置文件的导出导入部分花了我足足1个星期!而且由于它是基于事件发生的次序(SAX),似乎有时会发生一些无法控制的情况--例如进入某Level后忘了记录,结果……后面的程序全部死掉!这时想起同事之前推荐的 TinyXML,结果……用了不到3小时就把我的文件导出来了~~呵呵。在阅读本文之前,请先看看我Blog里转贴的《TinyXML学习笔记》,相信它能给各位一个关于TinyXML的初步概念。
言归正传,本文目的在于补全之前《TinyXML学习》的不足,尽量把常用的示例代码列出让大家参考。此外,在本篇最后会给出一个完整的文件读写例子,供读者参考。
1. 编程环境的设置。新建一个项目,起名叫TestTXML。到http://sourceforge.net/projects/tinyxml/ 下载TinyXML的官方例子,并编译第一个Project tinyxml(注意,最好编译Release的版本,代码比较小。然后把生成的tinyxml.lib(如果是Debug版本,叫tinyxmld.lib)连同tinystr.h和tinyxml.h一起Copy到TestTXML项目的目录中。在TestTXML项目里的头文件加入对TinyXML的引用:
#pragma comment(lib,"tinyxml.lib") // 链接Library
#include "tinyxml.h" // TinyXML的头文件
2. 建立一个XML文件:
char* sFilePath = "ikk_doc.xml"; // 文件名称
TiXmlDocument xmlDoc( sFilePath ); // 建立一个XML文件
TiXmlDeclaration Declaration( "1.0","gb2312", "yes" ); // 声明XML的属性
xmlDoc.InsertEndChild( Declaration ); // 写入基本的XML头结构
xmlDoc.SaveFile(); // 把XML文件写入硬盘
这时,在硬盘上的TestXML项目目录里,ikk_doc.xml文件已经被创建出来了。
3. 在XML文件里插入Element
所谓的Element,就是在XML里面的Tag,例如在
TiXmlElement* pElm = NULL;
pElm = new TiXmlElement( "resumes" ); //定义当前的子节点 pElmParent.InsertEndChild( *pElm ); // 把子节点插入父节点中
4. 在element里插入属性。在刚才例子中,name=”裕作”就是Resume的属性,其中name是属性的名字,”裕作”是属性的值。在当前子节点内插入属性的方法如下:
pElm->SetAttribute( "name", resume.sName );
5. 在XML里插入文本。在
TiXmlText* pText = NULL;
pText = new TiXmlText( "简历内容" ); // 定义文本的内容
pElmChild->InsertEndChild( *pText ); //把text子节点插入父节点中
在具备了以上背景知识之后,我们已经可以用TinyXML读写一个XML文件了。本文最后的程序将写入,然后重新读取一个XML文件到我们的结构里。这个XML文件的内容如下:
以下程序将建立ikk_doc.xml文件,然后重新把内容读取进内存:
#pragma comment(lib,"tinyxml.lib")
#include "string.h"
#include "stdio.h"
#include "tinyxml.h"
#define XML_FILE "ikk_doc.xml"
#define NAME_LENGTH 256 // 名字类字符的分配长度
#define SAFE_DELETE(x) {if(x) delete x; x=NULL;} // 安全删除new分配出来的变量空间
#define SAFE_DELETE_ARRAY(x) {if(x) delete[] x; x=NULL;} // 安全删除new分配出来的数组空间
#define XML_HEADER "" // XML文件头的定义
typedef unsigned int uint32;
// 技能的结构
typedef struct skill_s {
uint32 nLevel; // 技能的程度
char sName[ NAME_LENGTH ]; // 技能的名称
skill_s() {
nLevel = 0;
sName[0] = 0;
}
} skill_t;
// 简历的结构
typedef struct resume_s {
char sName[ NAME_LENGTH ]; // 名字
bool isMan; // 是否男性
uint32 nAge; // 年龄
uint32 nNumSkill; // 技能的数目
skill_t* pSkill; // 技能的结构
resume_s() {
sName[0] = 0;
isMan = false;
nAge = 0;
nNumSkill = 0;
pSkill = NULL;
}
} resume_t;
void exportSkill( TiXmlElement* pElmParent, skill_t skill )
{
int i;
char sBuf[NAME_LENGTH]; // 一个临时存放的字符串
TiXmlElement* pElm = NULL; // 一个指向Element的指针
TiXmlText* pText = NULL; // 一个指向Text的指针
pElm = new TiXmlElement( "skill" );
// 插入等级(以属性形式)
sprintf( sBuf, "%d", skill.nLevel ); // 把Skill的登记变成字符串临时存进sBuf里
pElm->SetAttribute( "level", sBuf ); // 把等级插入Skill里
// 插入技能名称(以子Element形式)
pText = new TiXmlText( skill.sName ); // 建立一个Skill的子Element(一个Text形式的子元素)
pElm->InsertEndChild( *pText ); // 把这个Skill的子Element插入Skill里
SAFE_DELETE( pText ); // 删除这个Text
// 最后把整个Resume的子节点插入到父节点中
pElmParent->InsertEndChild( *pElm );
}
void importSkill( TiXmlElement* pElm, skill_t* pSkill )
{
int i;
char sBuf[NAME_LENGTH]; // 一个临时存放的字符串
TiXmlElement* pElmChild = NULL; // 一个指向Element的指针
TiXmlText* pText = NULL; // 一个指向Text的指针
// 读取level
pSkill->nLevel = atoi( pElm->Attribute( "level" ) );
// 读取技能名称
strcpy( pSkill->sName, pElm->FirstChild()->Value() );
}
void exportResume( TiXmlElement* pElmParent, resume_t resume )
{
int i;
char sBuf[NAME_LENGTH]; // 一个临时存放的字符串
TiXmlElement* pElm = NULL; // 一个指向Element的指针
TiXmlElement* pElmChild = NULL; // 一个指向Element的指针
TiXmlText* pText = NULL; // 一个指向Text的指针
pElm = new TiXmlElement( "resume" );
// 插入名字(以属性形式)
pElm->SetAttribute( "name", resume.sName );
// 插入性别(以子Element形式)
pElmChild = new TiXmlElement( "gender" ); // 建立一个子Element叫Gender
if( resume.isMan )
pText = new TiXmlText( "男" ); // 建立一个Gender的子Element(一个Text形式的子元素)
else
pText = new TiXmlText( "女" ); // 建立一个Gender的子Element(一个Text形式的子元素)
pElmChild->InsertEndChild( *pText ); // 把这个Gender的子Element插入Gender里
pElm->InsertEndChild( *pElmChild ); // 把Gender插入到主Element里
SAFE_DELETE( pElmChild ); // 删除已经用完的Gender
SAFE_DELETE( pText ); // 删除这个Text
// 插入年龄(以子Element形式)
pElmChild = new TiXmlElement( "age" ); // 建立一个子Element叫Age
sprintf( sBuf, "%d", resume.nAge ); // 把Age变成字符串临时存进sBuf里
pText = new TiXmlText( sBuf ); // 建立一个Age的子Element(一个Text形式的子元素)
pElmChild->InsertEndChild( *pText ); // 把这个Age的子Element插入Age里
pElm->InsertEndChild( *pElmChild ); // 把Age插入到主Element里
SAFE_DELETE( pElmChild ); // 删除已经用完的Age
SAFE_DELETE( pText ); // 删除这个Text
// 插入技能子节点
pElmChild = new TiXmlElement( "skills" ); // 建立一个子Element叫Skills
sprintf( sBuf, "%d", resume.nNumSkill ); // 把Skill的数目变成字符串临时存进sBuf里
pElmChild->SetAttribute( "num", sBuf ); // 把这个Skills的属性插入Skills里
for( i=0; i
{
exportSkill( pElmChild, resume.pSkill[i] ); // 插入一项技能
}
pElm->InsertEndChild( *pElmChild ); // 把Skills插入到主Element里
SAFE_DELETE( pElmChild ); // 删除已经用完的Skills
SAFE_DELETE( pText ); // 删除这个Text
// 最后把整个Resume的子节点插入到父节点中
pElmParent->InsertEndChild( *pElm );
SAFE_DELETE( pElm ); // 删除子节点
}
void importResume( TiXmlElement* pElm, resume_t* pResume )
{
int i;
char sBuf[NAME_LENGTH]; // 一个临时存放的字符串
TiXmlElement* pElmChild = NULL; // 一个指向Element的指针
TiXmlElement* pElmGrandChild = NULL; // 一个指向Element的指针
TiXmlText* pText = NULL; // 一个指向Text的指针
// 读入"resume"子节点
strcpy( pResume->sName, pElm->Attribute( "name" ) );
// 读入"gender"子节点
pElmChild = pElm->FirstChildElement( "gender" );
if( strcmp( "男", pElmChild->FirstChild()->Value() ) == 0 )
pResume->isMan = true;
else
pResume->isMan = false;
// 读入"age"子节点
pElmChild = pElm->FirstChildElement( "age" );
pResume->nAge = atoi( pElmChild->FirstChild()->Value() );
// 读入"skills"子节点
pElmChild = pElm->FirstChildElement( "skills" );
pResume->nNumSkill = atoi( pElmChild->Attribute( "num" ) );
pResume->pSkill = new skill_t[pResume->nNumSkill];
pElmGrandChild = pElmChild->FirstChildElement( "skill" ); // 指向第一个Skill
for( i=0; i
importSkill( pElmGrandChild, &(pResume->pSkill[i]) ); // 读取一个Skill
pElmGrandChild = pElmGrandChild->NextSiblingElement(); // 指向下一个Skill
}
}
bool readXML( char* sFilePath, int* nNumResume, resume_t** ppResume ) {
int i; // 用做循环的变量
TiXmlElement* pElmChild = NULL; // 一个指向Element的指针
TiXmlDocument xmlDoc( sFilePath ); // 输入XML路径
if( !xmlDoc.LoadFile() ) // 读取XML并检查是否读入正确
return false;
TiXmlElement* pElmRoot = NULL; // 根节点
pElmRoot = xmlDoc.FirstChildElement( "resumes" ); // 得到根节点
if( !pElmRoot ) {
return false;
}
*nNumResume = atoi( pElmRoot->Attribute( "num" ) ); // 读取Resume的数目
*ppResume = new resume_t[*nNumResume]; // 分配Resume的空间
pElmChild = pElmRoot->FirstChildElement( "resume" ); // 找出第一个Resume
for( i=0; i<*nNumResume; i++ ) {
importResume( pElmChild, &((*ppResume)[i]) ); // 读取Resume的内容
pElmChild = pElmChild->NextSiblingElement(); // 找出下一个Resume
}
return true;
}
bool writeXML( char* sFilePath, int nNumResume, resume_t* pResume )
{
if( !sFilePath || !pResume )
return false; // 确定指针存在
int i; // 用做循环的变量
char sBuf[NAME_LENGTH]; // 一个临时存放的字符串
TiXmlElement* pElm = NULL; // 一个指向Element的指针
TiXmlDeclaration Declaration( "1.0","gb2312", "yes" ); // 建立XML头结构
TiXmlDocument xmlDoc( sFilePath ); // 用存档的文件名字来建立一个XML文件
xmlDoc.InsertEndChild( Declaration ); // 把XML头结构插入当前文档
// 插入根节点“Resumes”
pElm = new TiXmlElement( "resumes" ); // 建立根节点“Resumes”
sprintf( sBuf, "%d", nNumResume ); // 把nNumResume变成字符串临时存进sBuf里
pElm->SetAttribute( "num", sBuf ); // 建立一个Resumes的子Element
for( i=0; i<2; i++ )
{
exportResume( pElm, pResume[i] ); // 在根节点上插入以上定义的2个简历
}
xmlDoc.InsertEndChild( *pElm );
xmlDoc.SaveFile();
SAFE_DELETE( pElm ); // 删除Element
return true;
}
void main()
{
int i, j;
// + == 设置两份简历 ==========================================================
int nNumResume = 2;
resume_t* pResume = new resume_t[ nNumResume ];
// 1. 初始化第一份简历
strcpy( pResume[0].sName, "裕作" );
pResume[0].isMan = true;
pResume[0].nAge = 26;
pResume[0].nNumSkill = 2;
pResume[0].pSkill = new skill_t[2];
{ // 设置技能列表结构
strcpy( pResume[0].pSkill[0].sName, "编程" );
strcpy( pResume[0].pSkill[1].sName, "吹牛" );
pResume[0].pSkill[0].nLevel = 99;
pResume[0].pSkill[1].nLevel = 1;
}
// 2. 初始化第二份简历
strcpy( pResume[1].sName, "裕作 The Great" );
pResume[1].isMan = true;
pResume[1].nAge = 0;
pResume[1].nNumSkill = 1;
pResume[1].pSkill = new skill_t[1];
{ // 设置技能列表结构
strcpy( pResume[1].pSkill[0].sName, "编程" );
pResume[1].pSkill[0].nLevel = 100;
}
// - == 设置两份简历 ==========================================================
// 把简历以XML形式写入磁盘
if( !writeXML( XML_FILE, nNumResume, pResume ) )
{
printf( "ERROR: can't write the file." );
return;
}
// 删除Resume
nNumResume = 0;
SAFE_DELETE_ARRAY( pResume );
// 重新读入XML文件里的Resume数据
if( !readXML( XML_FILE, &nNumResume, &pResume ) )
{
printf( "ERROR: can't read the file." );
return;
}
// 把所有简历输出到屏幕
if( pResume ) // 确定有Resume
{
for( i=0; i
printf( "简历:======================\n" );
printf( "\t名字:%s\n", pResume[i].sName );
if( pResume[i].isMan )
printf( "\t性别:男\n" );
else
printf( "\t性别:女\n" );
printf( "\t年龄:%d\n", pResume[i].nAge );
printf( "\t职业技能:\n" );
for( j=0; j
printf( "\t\t技能名称:%s\n", pResume[i].pSkill[j].sName );
printf( "\t\t技能等级:%d\n", pResume[i].pSkill[j].nLevel );
}
}
}
}