[Section]
"key"="String Data"
"key"=dword: 十六进制数值
"key"=hex: 二进制
注意,二进制的写法如下
"pwd"=hex:31,32,33,34,35,36,37,38
2.2. ACE_Ini_ImpExp
从文件中导入字符串配置数据。充许 not-typed 值(没有 #,dword: hex:, 等前缀),在标准的.ini和.conf中跳过空白字符(tabs和spaces)。 值 (在等式的右边)可以被双引号限定,使得tabs或spaces能够留在字符串中。调用者必须自己转换字符串到类型。格式如下:
TimeToLive = 100
Delay = false
Flags = FF34 # 可以象这样写注释
Heading = "ACE - Adaptive Communication Environment"
3、一个友好的函数
使用此类配置文件时,如果用到会变化的配置集合,我们经常遇到这样的写法
[section]
"size"=dword:2
"item_1"="value1"
"item_2"="value2"
这样写因为 window 提供的 API 只能一项一项读取,我们只能在读取了size 的值后,才能拼凑出"item_1"键名来取到相应的值。在实际操作中维护人员很容易遗漏操作,增加了选项但忘记增加size的值。ACE则提供了非常友好的enumerate_values函数,配合一下 boost 的 split 使用起来感觉很好。
一个非常简单的TCP转发程序的配置文件,将一端口接收到的数据转发至指定地址的端口,可以开多个服务端口:
[server\listen_items]
;listen_port, target_ip, target_port, timeout (second), validate
"item_1"="19998,192.168.168.217,8101,60,1"
"item_2"="8000, 192.168.0.57, 23, 60, 1"
实际的代码摘录,但不一定能编译呵 :-)
1
2
#include <boost/algorithm/string.hpp>
3
#include <boost/lexical_cast.hpp>
4
using namespace boost;
5
6
7
class ListenItem
8
{
9
public:
10
unsigned int listen_port_;
11
string target_ip_;
12
unsigned int target_port_;
13
unsigned int timeout_;
14
bool validate_;
15
};
16
17
vector<ListenItem> vec;
18
19
int index = -1;
20
ACE_TString name;
21
ACE_Configuration::VALUETYPE type;
22
while(0 == config.enumerate_values(section, ++index, name, type))
23
{
24
ACE_TString str;
25
if(config.get_string_value(section, name.c_str(), str) == -1)
26
{
27
ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("ListenPort item does not exist\n")), -1);
28
}
29
30
ListenItem item;
31
vector<string> splitVec;
32
string ss = str.c_str();
33
split( splitVec, ss, is_any_of(",") );
34
item.listen_port_ = lexical_cast<unsigned int>(trim_copy(splitVec[0]));
35
item.target_ip_ = lexical_cast<string>(trim_copy(splitVec[1]));
36
item.target_port_ = lexical_cast<unsigned int>(trim_copy(splitVec[2]));
37
item.timeout_ = lexical_cast<unsigned int>(trim_copy(splitVec[3]));
38
item.validate_ = lexical_cast<bool>(trim_copy(splitVec[4]));
39
if(item.validate_)
40
vec.push_back(item);
41
42
}
43
44
45
这样就可以不写
1
stringstream s;
2
s << "item_" << i+1;
3
这样的代码了,也避免了维护人员遗漏操作
4、编译选项
上面代码有用到 boost 的相关内容,如果你使用的是 ACE Programmer's Guide 的 2.5 How to Build Your Applications 节所介绍的Makefile,在 linux 下面的话是不可少的
CPPFLAGS = -i"$(BOOST_ROOT)"
当然,还要在.bash_profile或相应原地方加入类似说明:
BOOST_ROOT=$HOME/boost_X_XX_X
export BOOST_ROOT
//WuErPing 补充 (2006/12/28 )
5、Use Unicode Character Set/Use Multi-Byte Character Set
上面的代码是使用Use Multi-Byte Character Set选项编译的,相应的编译ACE时也没有用到#define ACE_USES_WCHAR 1,如果使用Use Unicode Character Set是有问题的。要使写好的代码能同时在两个编译项中切换,除了利用ACE宏定义的ACE_TEXT,ACE_TString来处理字符串,用到的C++标准库string与stringstream时也需要做些处理。

完整源码示例
1
#ifndef _SIDLE_APP_CONFIG_
2
#define _SIDLE_APP_CONFIG_
3
4
#include <vector>
5
#include <string>
6
#include <sstream>
7
#include <boost/algorithm/string.hpp>
8
#include <boost/lexical_cast.hpp>
9
#include "ace/Configuration_Import_Export.h"
10
using namespace std;
11
using namespace boost;
12
13
namespace TempfileManager
14

{
15
typedef basic_string<ACE_TCHAR, char_traits<ACE_TCHAR>,
16
allocator<ACE_TCHAR> > stdstring;
17
typedef basic_stringstream<ACE_TCHAR, char_traits<ACE_TCHAR>,
18
allocator<ACE_TCHAR> > stdstringstream;
19
20
struct WorkInfo
21
{
22
stdstring name; // 命名
23
unsigned long interval; // 定时器间隔时间(秒)
24
unsigned long timeout; // 定时器超时(秒)
25
bool forceable; // 强制改变文件属性到普通
26
bool recursiveable; // 递归处理子目录及下面的文件
27
unsigned int hour; // 多少小时前的文件被处理 (小时)
28
unsigned int num; // 每次最多处理文件数
29
stdstring directory; // 目录
30
stdstring pattern; // 通配符
31
bool workable; // 是否交给定时器队列运行
32
};
33
34
class AppConfig
35
{
36
public:
37
const vector<WorkInfo>& WorkList() const
{return _workList;}
38
39
bool Open(ACE_TCHAR * inipath)
40
{
41
ACE_Configuration_Heap config;
42
if(config.open() == -1)
43
{
44
ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("config")), false);
45
}
46
ACE_Registry_ImpExp imp(config);
47
if(imp.import_config(inipath) == -1)
48
{
49
ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("Can't open config file")), false);
50
}
51
ACE_Configuration_Section_Key section;
52
if(config.open_section(config.root_section(), ACE_TEXT("WorkList"), 0, section) == -1)
53
{
54
ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("Can't open [WorkList] section")), false);
55
}
56
int index = -1;
57
ACE_TString name;
58
ACE_Configuration::VALUETYPE type;
59
while(0 == config.enumerate_values(section, ++index, name, type))
60
{
61
if(type == ACE_Configuration::STRING)
62
{
63
ACE_TString value;
64
if(config.get_string_value(section, name.c_str(), value) == -1)
65
{
66
ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("item does not exist\n")), false);
67
}
68
69
stdstring str = value.c_str();
70
WorkInfo item;
71
vector<stdstring> splitVec;
72
split(splitVec, str, is_any_of(ACE_TEXT(",")));
73
item.name = lexical_cast<stdstring>(trim_copy(splitVec[0]));
74
item.interval = lexical_cast<unsigned long>(trim_copy(splitVec[1]));
75
item.timeout = lexical_cast<unsigned long>(trim_copy(splitVec[2]));
76
item.forceable = lexical_cast<bool>(trim_copy(splitVec[3]));
77
item.recursiveable = lexical_cast<bool>(trim_copy(splitVec[4]));
78
item.hour = lexical_cast<unsigned int>(trim_copy(splitVec[5]));
79
item.num = lexical_cast<unsigned int>(trim_copy(splitVec[6]));
80
item.directory = lexical_cast<stdstring>(trim_copy(splitVec[7]));
81
item.pattern = lexical_cast<stdstring>(trim_copy(splitVec[8]));
82
item.workable = lexical_cast<bool>(trim_copy(splitVec[9]));
83
if(item.workable)
84
_workList.push_back(item);
85
}
86
}
87
return true;
88
}
89
90
const stdstring ToString()
91
{
92
stdstringstream ss;
93
for(vector<WorkInfo>::iterator iter = _workList.begin(); iter != _workList.end(); ++iter)
94
{
95
ss << "work = " << iter->name << "\n";
96
ss << "interval = " << iter->interval << "\n";
97
ss << "timeout = " << iter->timeout << "\n";
98
ss << "forceable = " << iter->forceable << "\n";
99
ss << "recursiveable = " << iter->recursiveable << "\n";
100
ss << "hour = " << iter->hour << "\n";
101
ss << "num = " << iter->num << "\n";
102
ss << "directory = " << iter->directory << "\n";
103
ss << "pattern = " << iter->pattern << "\n";
104
ss << "workable = " << iter->workable << "\n";
105
ss << "\n";
106
}
107
return ss.str();
108
}
109
110
private:
111
vector<WorkInfo> _workList;
112
};
113
}
114
#endif

配置文件
1
[WorkList]
2
;定时器名称(不可以有逗号)
3
;定时器间隔(second)
4
;定时器超时(second)
5
;是否强制修改文件属性为普通(0:不处理, 1:处理)
6
;是否递归处理(0:不递归, 1:递归)
7
;多少小时前的被删除
8
;一次最多处理多少个,
9
;要处理的目录名
10
;work是否提交给定时器运行
11
"work_1"="clear D:/temp/qzx, 2, 10, 0, 0, 48, 1, D:/temp/qzx/, *.jpg, 1 "
12
--
写配置文件注意:
1、写完最后一行要加回车换行
2、""="",等于号与引号之间不能有空格