1、什么是RabbitMQ工作队列
我们在应用程序使用消息系统时,一般情况下生产者往队列里插入数据时速度是比较快的,但是消费者消费数据往往涉及到一些业务逻辑处理导致速度跟不上生产者生产数据。因此如果一个生产者对应一个消费者的话,很容易导致很多消息堆积在队列里。这时,就得使用工作队列了。一个队列有多个消费者同时消费数据。
下图取自于官方网站(RabbitMQ)的工作队列的图例
P:消息的生产者
C1:消息的消费者1
C2:消息的消费者2
红色:队列
生产者将消息发送到队列,多个消费者同时从队列中获取消息。
工作队列有两种分发数据的方式:轮询分发(Round-robin)和 公平分发(Fair dispatch)。轮询分发:队列给每一个消费者发送数量一样的数据。公平分发:消费者设置每次从队列中取一条数据,并且消费完后手动应答,继续从队列取下一个数据。下面分别是两种分发方式不同的写法。
2、轮询分发(Round-robin)
生产者(Send)生产10条数据,消费者1(Receive1)接收数据并假设处理业务逻辑1s,消费者2(Receive2)接收数据并假设处理业务逻辑2s(生产者先运行,两个消费者同时运行)。
2.1、生产者(Send)代码
public class Send
{
//队列名称
private static final String QUEUE_NAME = "test_work_round_robin_queue";
public static void main(String[] args)
{
try
{
//获取连接
Connection connection = ConnectionUtil.getConnection();
//从连接中获取一个通道
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
for (int i = 0; i < 10; i++)
{
String message = "this is work_round_robin queue message" + i;
System.out.println("[send]:" + message);
//发送消息
channel.basicPublish("", QUEUE_NAME, null, message.getBytes("utf-8"));
Thread.sleep(20 * i);
}
channel.close();
connection.close();
}
catch (IOException | TimeoutException | InterruptedException e)
{
e.printStackTrace();
}
}
}
运行结果:
[send]:this is work_round_robin queue message0
[send]:this is work_round_robin queue message1
[send]:this is work_round_robin queue message2
[send]:this is work_round_robin queue message3
[send]:this is work_round_robin queue message4
[send]:this is work_round_robin queue message5
[send]:this is work_round_robin queue message6
[send]:this is work_round_robin queue message7
[send]:this is work_round_robin queue message8
[send]:this is work_round_robin queue message9
2.2、消费者1(Receive1)代码
public class Receive1
{
//队列名称
private static final String QUEUE_NAME = "test_work_round_robin_queue";
public static void main(String[] args)
{
try
{
//获取连接
Connection connection = ConnectionUtil.getConnection();
//从连接中获取一个通道
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//定义消费者
DefaultConsumer consumer = new DefaultConsumer(channel)
{
//当消息到达时执行回调方法
@Override
public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties,
byte[] body) throws IOException
{
String message = new String(body, "utf-8");
System.out.println("[1] Receive message:" + message);
try
{
//消费者休息1s处理业务
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
finally
{
System.out.println("[1] done");
}
}
};
//监听队列
channel.basicConsume(QUEUE_NAME, true, consumer);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
运行结果:
[1] Receive message:this is work_round_robin queue message0
[1] done
[1] Receive message:this is work_round_robin queue message2
[1] done
[1] Receive message:this is work_round_robin queue message4
[1] done
[1] Receive message:this is work_round_robin queue message6
[1] done
[1] Receive message:this is work_round_robin queue message8
[1] done
2.3、消费者2(Receive2)代码
public class Receive2
{
//队列名称
private static final String QUEUE_NAME = "test_work_round_robin_queue";
public static void main(String[] args)
{
try
{
//获取连接
Connection connection = ConnectionUtil.getConnection();
//从连接中获取一个通道
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//定义消费者
DefaultConsumer consumer = new DefaultConsumer(channel)
{
//当消息到达时执行回调方法
@Override
public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties,
byte[] body) throws IOException
{
String message = new String(body, "utf-8");
System.out.println("[2] Receive message:" + message);
try
{
//消费者休息2s处理业务
Thread.sleep(2000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
finally
{
System.out.println("[2] done");
}
}
};
//监听队列
channel.basicConsume(QUEUE_NAME, true, consumer);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
运行结果:
[2] Receive message:this is work_round_robin queue message1
[2] done
[2] Receive message:this is work_round_robin queue message3
[2] done
[2] Receive message:this is work_round_robin queue message5
[2] done
[2] Receive message:this is work_round_robin queue message7
[2] done
[2] Receive message:this is work_round_robin queue message9
[2] done
总结:两个消费者得到的数据量一样的。从运行时可以看到消费者1会先执行完,消费者2会后执行完。并不会因为两个消费者处理数据速度不一样使得两个消费者取得不一样数量的数据。并且当队列数量大的时候通过观察RabbitMQ的管理后台,可以看到管理界面队列中的数据很快就没了,但是这个时候两个消费者其实并没有消费完数据。这种分发方式存在着很大的隐患。
3、公平分发(Fair dispatch)
生产者(Send)生产10条数据,消费者1(Receive1)接收数据并假设处理业务逻辑1s,消费者2(Receive2)接收数据并假设处理业务逻辑2s(生产者先运行,两个消费者同时运行)。
消费者设置每次从队列里取一条数据,并且关闭自动回复机制,每次取完一条数据后,手动回复并继续取下一条数据。
3.1、生产者(Send)代码
public class Send
{
//队列名称
private static final String QUEUE_NAME = "test_work_fair_dispatch_queue";
public static void main(String[] args)
{
try
{
//获取连接
Connection connection = ConnectionUtil.getConnection();
//从连接中获取一个通道
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
for (int i = 0; i < 10; i++)
{
String message = "this is work_fair_dispatch queue message" + i;
System.out.println("[send]:" + message);
//发送消息
channel.basicPublish("", QUEUE_NAME, null, message.getBytes("utf-8"));
Thread.sleep(20 * i);
}
channel.close();
connection.close();
}
catch (IOException | TimeoutException | InterruptedException e)
{
e.printStackTrace();
}
}
}
运行结果:
[send]:this is work_fair_dispatch queue message0
[send]:this is work_fair_dispatch queue message1
[send]:this is work_fair_dispatch queue message2
[send]:this is work_fair_dispatch queue message3
[send]:this is work_fair_dispatch queue message4
[send]:this is work_fair_dispatch queue message5
[send]:this is work_fair_dispatch queue message6
[send]:this is work_fair_dispatch queue message7
[send]:this is work_fair_dispatch queue message8
[send]:this is work_fair_dispatch queue message9
3.2、消费者1(Receive1)代码
public class Receive1
{
//队列名称
private static final String QUEUE_NAME = "test_work_fair_dispatch_queue";
public static void main(String[] args)
{
try
{
//获取连接
Connection connection = ConnectionUtil.getConnection();
//从连接中获取一个通道
final Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//设置每次从队列里取一条数据
int prefetchCount = 1;
channel.basicQos(prefetchCount);
//定义消费者
DefaultConsumer consumer = new DefaultConsumer(channel)
{
//当消息到达时执行回调方法
@Override
public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties,
byte[] body) throws IOException
{
String message = new String(body, "utf-8");
System.out.println("[1] Receive message:" + message);
try
{
//消费者休息1s处理业务
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
finally
{
System.out.println("[1] done");
//手动应答
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
};
//设置手动应答
boolean autoAck = false;
//监听队列
channel.basicConsume(QUEUE_NAME, autoAck, consumer);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
运行结果:
[1] Receive message:this is work_fair_dispatch queue message1
[1] done
[1] Receive message:this is work_fair_dispatch queue message2
[1] done
[1] Receive message:this is work_fair_dispatch queue message4
[1] done
[1] Receive message:this is work_fair_dispatch queue message5
[1] done
[1] Receive message:this is work_fair_dispatch queue message7
[1] done
[1] Receive message:this is work_fair_dispatch queue message8
[1] done
3.3、消费者2(Receive2)代码
public class Receive2
{
//队列名称
private static final String QUEUE_NAME = "test_work_fair_dispatch_queue";
public static void main(String[] args)
{
try
{
//获取连接
Connection connection = ConnectionUtil.getConnection();
//从连接中获取一个通道
final Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//保证一次只分发一个
int prefetchCount = 1;
channel.basicQos(prefetchCount);
//定义消费者
DefaultConsumer consumer = new DefaultConsumer(channel)
{
//当消息到达时执行回调方法
@Override
public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties,
byte[] body) throws IOException
{
String message = new String(body, "utf-8");
System.out.println("[2] Receive message:" + message);
try
{
//消费者休息2s处理业务
Thread.sleep(2000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
finally
{
System.out.println("[2] done");
//手动应答
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
};
//设置手动应答
boolean autoAck = false;
//监听队列
channel.basicConsume(QUEUE_NAME, autoAck, consumer);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
运行结果:
[2] Receive message:this is work_fair_dispatch queue message0
[2] done
[2] Receive message:this is work_fair_dispatch queue message3
[2] done
[2] Receive message:this is work_fair_dispatch queue message6
[2] done
[2] Receive message:this is work_fair_dispatch queue message9
[2] done
总结:消费者1处理了6条数据,消费者2处理了4条数据
与轮询分发不同的是,当每个消费都设置了每次只会从队列取一条数据时,并且关闭自动应答,在每次处理完数据后手动给队列发送确认收到数据。这样队列就会公平给每个消息费者发送数据,消费一条再发第二条,而且可以在管理界面中看到数据是一条条随着消费者消费完从而减少的,并不是一下子全部分发完了。显然公平分发更符合系统设计。
// 创建人: litao;
// 创建时间: 2016-11-1;
#pragma once
#include
class XmlNode
{
friend class FastXML;
private:
XmlNode();
public:
XmlNode(const char *tagname);
virtual ~XmlNode();
public:
//删除自己;
bool remove();
//增加子节点;
XmlNode* addChild(XmlNode* newChild);
//删除子节点;
void removeChild(XmlNode* nodeChild);
//去掉内存节点,不释放;
void removeAllChildNoDel();
//设置节点值;
void setNodeValue(const char * nodeval);
//获取节点值;
std::string getNodeValue();
//删除属性;
void removeAtrr(const char * attr);
//设置属性值;
void setAttribute(const char * attr,const char * val);
//获取节点名称;
std::string getTagName();
//获取属性值;
std::string getAttribute(const char * attr);
//获得父节点;
XmlNode *getParent();
//获得节点的xml文本,含所有子节点;
std::string getNodeText();
//获取所有节点文本值;
std::string getAllChildNodeText();
//获得所有属性名;
std::vector
//获得所有属性名和属性值;
void getAttributes(std::vector
//获得所有子节点;
std::vector
//根据名称获取第一个节点;
XmlNode* getFirstChildByTagName(std::string tagname);
//获得指定名称的子节点;
std::vector
//根据名称查找子孙节点(也包含当前节点);
std::vector
//根据名称查找节点;
void findChildNodeByTagName(std::string const& tagname, std::vector
//获取叶子节点;
void getAllLeafNode(std::vector
//是否有孩子节点;
bool hasChild();
private:
std::vector
std::vector
std::string m_tagName;
std::vector
std::string m_nodevalue;
XmlNode *m_parent;
std::map
bool m_bmap;
private:
void clearAll();
void buildMap();
};
class FastXML
{
public:
FastXML(void);
~FastXML(void);
public:
//从文件加载;
bool load(const char *filePath);
//加载Utf8内存块;
bool loadFromUtf8Buff(const char *pBuff,int nsize);
//加载ansi内存块;
bool loadFromBuff(const char *pBuff);
//保存文件;
bool save(const char *filepath);
//获取文本字符串;
std::string getFileXML();
//获取文件内容(不含头);
std::string getDoc();
//获取根节点;
XmlNode* getRootNode();
//添加一个根节点;
void addRootNode(XmlNode *pNode);
//设置文件头();
void setXmlHead(std::string strhead);
//获取所有的节点数;
void getNodeSize(XmlNode *pNode,std::string tagname,int &nSize);
public:
void replaceAttr(std::string Attr,std::string oldvalue,std::string newvalue,XmlNode *pNode=NULL);
private:
void decComment(char *&pBuffer);
void decHeadCode(char *&pBuffer);
XmlNode* parserBuffer(char *pBuffer,XmlNode *pParent);
std::string trimRight(const std::string& str);
void inline skipSpace(char *&pBuffer);
std::string utf8ToAnsi(const char * pszUTF8,int nLen,int* pnFailed);
void ansiToUtf8( std::string &strbuff);
int decodeCharUTF8( const char*& pszUTF8 );
void encodeCharUTF8( int nUChar, char* pszUTF8, int& nUTF8Len );
private:
XmlNode m_rootNode;
std::string m_xmlhead;
std::string m_doctype;
std::string m_datatype;
std::vector
};
// 创建人: litao;
// 创建时间: 2016-11-1;
#include "Fastxml.h"
#include
#include
using namespace std;
string& replace_all_distinct(string& str,const string& old_value,const string& new_value)
{
for(string::size_type pos(0); pos!=string::npos; pos+=new_value.length())
{
if((pos=str.find(old_value,pos))!=string::npos)
{
str.replace(pos,old_value.length(),new_value);
}
else
{
break;
}
}
return str;
}
XmlNode::XmlNode()
{
}
XmlNode::XmlNode(const char *tagname):m_parent(NULL),m_bmap(false)
{
if(tagname)
{
m_tagName = tagname;
}
}
XmlNode::~XmlNode()
{
clearAll();
}
XmlNode* XmlNode::addChild(XmlNode* newChild)
{
newChild->m_parent = this;
m_vcChildNode.push_back(newChild);
return newChild;
}
std::string XmlNode::getTagName()
{
return m_tagName;
}
std::string XmlNode::getAttribute(const char * attr)
{
if(attr)
{
buildMap();
if(m_AttrMap.size() == 0)
return "";
if(m_AttrMap.count(attr))
{
return m_AttrMap[attr];
}
}
return "";
}
XmlNode *XmlNode::getParent()
{
return m_parent;
}
void XmlNode::clearAll()
{
for (size_t i = 0;i < m_vcChildNode.size(); ++i)
{
delete m_vcChildNode[i];
}
m_vcChildNode.clear();
m_AttrMap.clear();
m_vcattr.clear();
m_vcval.clear();
m_parent = NULL;
m_tagName.clear();
m_nodevalue.clear();
}
void XmlNode::setAttribute(const char * attr,const char * val)
{
_ASSERT(attr && val);
if(!attr || !val)
return;
if(strlen(val)==0)
return;
m_bmap = false;
bool bExist = false;
for (size_t i = 0 ;i < m_vcattr.size(); ++i)
{
if(m_vcattr[i] == attr)
{
bExist = true;
m_vcval[i] = val;
}
}
if(!bExist)
{
m_vcattr.push_back(attr);
m_vcval.push_back(val);
}
}
void XmlNode::buildMap()
{
if(!m_bmap)
{
m_bmap = true;
_ASSERT(m_vcattr.size() == m_vcval.size());
m_AttrMap.clear();
for (size_t i = 0;i < m_vcattr.size(); ++i)
{
m_AttrMap.insert(std::pair
}
}
}
void XmlNode::getAttributes(std::vector
{
vcAttr = m_vcattr;
vcVal = m_vcval;
}
std::vector
{
return m_vcChildNode;
}
void XmlNode::setNodeValue(const char * nodeval)
{
if(nodeval)
m_nodevalue = nodeval;
}
std::string XmlNode::getNodeValue()
{
return m_nodevalue;
}
bool XmlNode::remove()
{
XmlNode *pParent = getParent();
if(pParent)
{
pParent->removeChild(this);
return true;
}
return false;
}
void XmlNode::removeChild(XmlNode* nodeChild)
{
for (size_t i = 0; i< m_vcChildNode.size(); ++i)
{
if(m_vcChildNode[i] == nodeChild)
{
m_vcChildNode.erase(m_vcChildNode.begin()+i);
delete nodeChild;
break;
}
}
}
void XmlNode::removeAllChildNoDel()
{
m_vcChildNode.clear();
}
void XmlNode::removeAtrr(const char * attr)
{
for (size_t i = 0;i < m_vcattr.size(); ++i)
{
if(m_vcattr[i] == attr)
{
m_vcattr.erase(m_vcattr.begin()+i);
m_vcval.erase(m_vcval.begin()+i);
m_bmap = false;
break;
}
}
}
std::string XmlNode::getAllChildNodeText()
{
std::string xmltext;
size_t nChildLen = m_vcChildNode.size();
for (size_t i = 0; i < nChildLen; ++i)
{
XmlNode* pNode = m_vcChildNode[i];
std::string elexmltext = pNode->getNodeText();
xmltext += elexmltext;
}
return xmltext;
}
std::string XmlNode::getNodeText()
{
std::string xmltext;
xmltext += "<";
xmltext += m_tagName;
_ASSERT(m_vcattr.size() == m_vcval.size());
size_t nattrsize = m_vcattr.size();
for (size_t i = 0; i < nattrsize; ++i)
{
if(m_vcattr[i].length() > 0)
{
xmltext += " ";
xmltext += m_vcattr[i];
xmltext +="=\"";
xmltext += m_vcval[i];
xmltext += "\"";
}
}
//是否有子节点;
size_t nChildLen = m_vcChildNode.size();
if(nChildLen)
{
xmltext += ">\r\n";
for (size_t i = 0; i < nChildLen; ++i)
{
XmlNode* pNode = m_vcChildNode[i];
std::string elexmltext = pNode->getNodeText();
xmltext += elexmltext;
}
xmltext += m_nodevalue;
xmltext +="";
xmltext += m_tagName;
xmltext +=">\r\n";
}
else
{
//没子节点就结束;
if(m_nodevalue.length() > 0)
{
xmltext += ">";
xmltext += m_nodevalue;
xmltext +="";
xmltext += m_tagName;
xmltext +=">\r\n";
}
else
{
xmltext += "/>\r\n";
}
}
return xmltext;
}
std::vector
{
return m_vcattr;
}
XmlNode* XmlNode::getFirstChildByTagName(std::string tagname)
{
std::vector
if(tagNodes.size() >0)
return tagNodes[0];
return NULL;
}
std::vector
{
std::vector
for (size_t i = 0; i
if(m_vcChildNode[i]->m_tagName == tagname)
{
vcChildNode.push_back(m_vcChildNode[i]);
}
}
return vcChildNode;
}
std::vector
{
std::vector
if(m_tagName == tagname)
{
vcChildNode.push_back(this);
}
for (size_t i = 0; i
std::vector
for (size_t j = 0; j < vcNextChild.size(); ++j)
{
vcChildNode.push_back(vcNextChild[j]);
}
}
return vcChildNode;
}
void XmlNode::findChildNodeByTagName( std::string const& tagname, std::vector
{
if ( m_tagName == tagname )
{
pnodes.push_back(this);
}
for (std::vector
Iter != m_vcChildNode.end(); ++Iter )
{
(*Iter)->findChildNodeByTagName(tagname, pnodes);
}
}
void XmlNode::getAllLeafNode(std::vector
{
std::vector
if(vcChild.size() == 0)
{
vcLeafNode.push_back(this);
}
else
{
for (size_t i = 0; i < vcChild.size(); ++i)
{
vcChild[i]->getAllLeafNode(vcLeafNode);
}
}
}
bool XmlNode::hasChild()
{
if(m_vcChildNode.size() > 0)
return true;
return false;
}
void FastXML::encodeCharUTF8( int nUChar, char* pszUTF8, int& nUTF8Len)
{
if ( ! (nUChar & ~0x0000007f) ) // < 0x80
{
if ( pszUTF8 )
pszUTF8[nUTF8Len++] = (char)nUChar;
else
++nUTF8Len;
}
else if ( ! (nUChar & ~0x000007ff) ) // < 0x800
{
if ( pszUTF8 )
{
pszUTF8[nUTF8Len++] = (char)(((nUChar&0x7c0)>>6)|0xc0);
pszUTF8[nUTF8Len++] = (char)((nUChar&0x3f)|0x80);
}
else
nUTF8Len += 2;
}
else if ( ! (nUChar & ~0x0000ffff) ) // < 0x10000
{
if ( pszUTF8 )
{
pszUTF8[nUTF8Len++] = (char)(((nUChar&0xf000)>>12)|0xe0);
pszUTF8[nUTF8Len++] = (char)(((nUChar&0xfc0)>>6)|0x80);
pszUTF8[nUTF8Len++] = (char)((nUChar&0x3f)|0x80);
}
else
nUTF8Len += 3;
}
else // < 0x110000
{
if ( pszUTF8 )
{
pszUTF8[nUTF8Len++] = (char)(((nUChar&0x1c0000)>>18)|0xf0);
pszUTF8[nUTF8Len++] = (char)(((nUChar&0x3f000)>>12)|0x80);
pszUTF8[nUTF8Len++] = (char)(((nUChar&0xfc0)>>6)|0x80);
pszUTF8[nUTF8Len++] = (char)((nUChar&0x3f)|0x80);
}
else
nUTF8Len += 4;
}
}
void FastXML::ansiToUtf8( std::string &strbuff)
{
std::string strUTF8;
int nUChar, nCharLen;
wchar_t wcChar;
char szUTF8Char[4];
const char *pANSI = strbuff.c_str();
while ( *pANSI )
{
nCharLen = mbtowc( &wcChar, pANSI, 5 );
if ( nCharLen < 1 )
{
nCharLen = 1;
wcChar = (wchar_t)' ';
}
pANSI += nCharLen;
nUChar = (int)wcChar;
nCharLen = 0;
encodeCharUTF8( nUChar, szUTF8Char, nCharLen );
strUTF8.append(szUTF8Char,nCharLen);
}
strbuff = strUTF8;
}
int FastXML::decodeCharUTF8(const char*& pszUTF8)
{
int nUChar = (unsigned char)*pszUTF8;
++pszUTF8;
if ( nUChar & 0x80 )
{
int nExtraChars;
if ( ! (nUChar & 0x20) )
{
nExtraChars = 1;
nUChar &= 0x1f;
}
else if ( ! (nUChar & 0x10) )
{
nExtraChars = 2;
nUChar &= 0x0f;
}
else if ( ! (nUChar & 0x08) )
{
nExtraChars = 3;
nUChar &= 0x07;
}
else
return -1;
while ( nExtraChars-- )
{
if ( (*pszUTF8 & 0x80) )
{
nUChar = nUChar<<6;
nUChar |= *pszUTF8 & 0x3f;
}
else
return -1;
++pszUTF8;
}
}
return nUChar;
}
std::string FastXML::utf8ToAnsi(const char * pszUTF8,int nLen,int* pnFailed)
{
std::string strANSI;
int nBufferLen = nLen + 4;
strANSI.reserve(nBufferLen);
int nUChar, nCharLen;
char szANSI[2];
if ( pnFailed )
*pnFailed = 0;
const char* pUTF8 = pszUTF8;
while ( *pUTF8 )
{
nUChar = decodeCharUTF8( pUTF8 );
if ( nUChar & ~0xffff )
nCharLen = -1;
else
wctomb_s(&nCharLen,szANSI,MB_CUR_MAX,(wchar_t)nUChar);
if ( nCharLen == -1 )
{
if ( pnFailed )
++(*pnFailed);
}
else
{
strANSI.append(szANSI,nCharLen);
}
}
return strANSI;
}
FastXML::FastXML(void)
{
m_xmlhead = "";
setlocale(LC_ALL, "");
}
FastXML::~FastXML(void)
{
}
std::string FastXML::trimRight(const std::string& str)
{
if (str.begin() == str.end())
{
return str;
}
std::string t = str;
for (std::string::iterator i = t.end() - 1; i != t.begin(); i--) {
if (!isspace(*i)) {
t.erase(i + 1, t.end());
break;
}
}
return t;
}
void inline FastXML::skipSpace(char *&pBuffer)
{
while(pBuffer && (*pBuffer == ' ' || *pBuffer == '\t' || *pBuffer == '\r' || *pBuffer == '\n'))
{
pBuffer++;
if(*pBuffer==0)
{
pBuffer--;
break;
}
}
}
void FastXML::decComment(char *&pBuffer)
{
skipSpace(pBuffer);
while(strncmp(pBuffer,"