一、前言
在公司从事嵌入式软件工作,应用层程序有QT平台的也有Android平台的,我主要负责QT方面的内容,系统为Linux。但公司的产品具有多个国家的版本,导致开机的动态画面、应用程序的菜单Logo、产品出厂厂商、公司网址也不一样,有的版本会带蓝牙,有的不带蓝牙,有的版本图像融合需要勾边,而有的不需要,在维护时极其不方便,如果应用程序修改了一个功能,所有版本都需要升级,那么升级小包的个数应该是 m * 2^2个,所以为了方便维护,减轻本部门以及测试组同事的工作量,把各个版本用一个小包与一个配置文件进行代替;即实现程序的可配置方式启动。
原理就是把配置文件放在相对应的路径,比如我测试就放在/home/目录下,在QT程序启动初始化参数的时候就开始读取配置文件,根据配置文件的参数来设置QT程序版本、蓝牙、融合勾边的全局变量参数,在实现加载资源的代码处添加if判断全局变量的参数,而执行不同的代码。同时,读取配置文件的字符串也能实现不同资源的加载,只要把与配置文件同名的文件资源放在一个目录下,用绝对路径调用该资源就行了。下面主要介绍读取配置文件的实现。
二、配置文件及读配置文件的程序
为保证读到的配置文件时正确的,要注意配置文件的格式,比如“=”前后是否有空格,图片名字一定要对应系统目录下资源图片的名字:
配置文件如下:
[Boot]
LogoImage = xxxx.jpg //开机Logo
[FactoryInfo]
China=1//版本
India=0
Trotect=0
Bluetooth=0//蓝牙
MergePlus=1//勾边 (我的程序只读到该行就break了,结束了while循环)
Company=0//公司厂商
Link=0//公司网址
SatLogo=0
Screensaver=0//屏保
#Company=0: 公司1111111111
#Company=1: 公司2222222222
#Company=2: 公司3333333333
#Link=0: http://www.公司1111111111
#Link=1: http://www.公司2222222222
#Link=2: http://www.公司3333333333
#Logo=0:on, screensaver-1.png, for 公司11111111111,Serial Num=9103xxxx
#Logo=1:off, screensaver-2.png, for 公司2222222222,Serial Num=P6201xxxx
#Logo=2:off, screensaver-3.png, for 公司3333333333,Serial Num=9103xxxx
#Screensaver=0:screensaver-1
#Screensaver=1:screensaver-2
#Screensaver=2:screensaver-3
#Screensaver=3:screensaver-4
#Screensaver=4:screensaver-5
#Screensaver=5:screensaver-6
读配置文件的程序
int TAnalysisView::read_conf(void)//QT类中的一个方法,也就跟一个函数差不多,用C语言实现
{
char conffile[]="/home/FactoryInfo.conf";//设置配置文件的路径,我只是测试暂时放这个目录下
int line = 0;
char *str;
FILE *fp;
int value;
if((fp = fopen(conffile,"r")) == NULL)//打开配置文件
{
printf("cannot open this file\n");
return 1;
}
char buf[BUF_SIZE_CONF];/BUF_SIZE_CONF //常量不用在意
memset(buf,0,BUF_SIZE_CONF);//初始化buf
while((str = fgets(buf, BUF_SIZE_CONF, fp)) != NULL){//逐行读取
char *entry_name;
char *entry_value;
line++;
if (buf[BUF_SIZE_CONF - 2] != '\0') {
printf("%s: line %d too long\n", conffile, line);
break;
}
if (str==NULL || *entry_name == '#')//空行或者#不读取
continue;
entry_name = strsep(&str, "=");//分解字符串为一组字符串
if (strcasecmp(entry_name, "China") == 0) {//忽略大小写比较字符串
entry_value = strsep(&str, "\0");
value = atoi(entry_value);//把字符串转换成整型数
if(value == 1){
//qWarning("[%s, %d]-----set_China true-----", __FILE__, __LINE__);
TGlobal::set_china(true);//设置全局变量参数
}
} else if (strcasecmp(entry_name, "India") == 0) {
entry_value = strsep(&str, "\0");
value = atoi(entry_value);
if(value == 1){
//qWarning("[%s, %d]-----set_India true-----", __FILE__, __LINE__);
TGlobal::set_India(true);//设置全局变量参数
}
} else if (strcasecmp(entry_name, "Trotect") == 0) {
entry_value = strsep(&str, "\0");
value = atoi(entry_value);
if(value == 1){
//qWarning("[%s, %d]-----set_Trotect true-----", __FILE__, __LINE__);
TGlobal::set_Trotect(true);//设置全局变量参数
}
} else if (strcasecmp(entry_name, "Bluetooth") == 0) {
entry_value = strsep(&str, "\0");
value = atoi(entry_value);
if(value == 1){
TGlobal::set_bluetooth(true);//设置全局变量参数
}
} else if (strcasecmp(entry_name, "MergePlus") == 0) {
entry_value = strsep(&str, "\0");
value = atoi(entry_value);
if(value == 1){
TGlobal::set_mergePlus(true);//设置全局变量参数
}
break;//控制读取到该参数在退出while()循环
}
memset(buf,0,BUF_SIZE_CONF);
}
fclose(fp);
return 0;
}
只需要在QT初始化时调用读取配置文件的方法即可。当然会也会遇到QT应用程序还没初始化就需要区分版本,可以直接用QT库中的类读取配置文件,如下:
Config cfg("FactoryInfo");//读取配置文件的名字,该文件应为FactoryInfo.conf,以.conf结尾
cfg.setGroup("FactoryInfo");//读取配置文件内中的分组,FactoryInfo
int lang = cfg.readNumEntry("China", 0);//读分组下面的China值为1
Config源码的config.h
#ifndef CONFIG_H
#define CONFIG_H
#include <qmap.h>
#include <qstringlist.h>
class Config
{
public:
typedef QMap< QString, QString > ConfigGroup;
Config( const QString &fn );
~Config();
void setGroup( const QString &gname );
void writeEntry( const QString &key, const QString &value );
void writeEntry( const QString &key, int num );
#ifdef Q_HAS_BOOL_TYPE
void writeEntry( const QString &key, bool b );
#endif
void writeEntry( const QString &key, const QStringList &lst, const QChar &sep );
QString readEntry( const QString &key, const QString &deflt = QString::null );
int readNumEntry( const QString &key, int deflt = -1 );
bool readBoolEntry( const QString &key, bool deflt = FALSE );
QStringList readListEntry( const QString &key, const QChar &sep );
void clearGroup();
void write( const QString &fn = QString::null );
protected:
void read();
void parse( const QString &line );
QMap< QString, ConfigGroup > groups;
QMap< QString, ConfigGroup >::Iterator git;
QString filename;
};
#endif
config.cpp的源码
#include "config.h"
#include <qfile.h>
#include <qfileinfo.h>
#include <qtextstream.h>
Config::Config( const QString &fn )
: filename( fn )
{
git = groups.end();
read();
}
Config::~Config()
{
write();
}
void Config::setGroup( const QString &gname )
{
QMap< QString, ConfigGroup>::Iterator it = groups.find( gname );
if ( it == groups.end() ) {
ConfigGroup *grp = new ConfigGroup;
git = groups.insert( gname, *grp );
return;
}
git = it;
}
void Config::writeEntry( const QString &key, const QString &value )
{
if ( git == groups.end() ) {
qWarning( "no group set" );
return;
}
( *git ).insert( key, value );
}
void Config::writeEntry( const QString &key, int num )
{
QString s;
s.setNum( num );
writeEntry( key, s );
}
#ifdef Q_HAS_BOOL_TYPE
void Config::writeEntry( const QString &key, bool b )
{
QString s;
s.setNum( ( int )b );
writeEntry( key, s );
}
#endif
void Config::writeEntry( const QString &key, const QStringList &lst, const QChar &sep )
{
QString s;
QStringList::ConstIterator it = lst.begin();
for ( ; it != lst.end(); ++it )
s += *it + sep;
writeEntry( key, s );
}
QString Config::readEntry( const QString &key, const QString &deflt )
{
if ( git == groups.end() ) {
//qWarning( "no group set" );
return deflt;
}
ConfigGroup::Iterator it = ( *git ).find( key );
if ( it != ( *git ).end() )
return *it;
else
return deflt;
}
int Config::readNumEntry( const QString &key, int deflt )
{
QString s = readEntry( key );
if ( s.isEmpty() )
return deflt;
else
return s.toInt();
}
bool Config::readBoolEntry( const QString &key, bool deflt )
{
QString s = readEntry( key );
if ( s.isEmpty() )
return deflt;
else
return (bool)s.toInt();
}
QStringList Config::readListEntry( const QString &key, const QChar &sep )
{
QString s = readEntry( key );
if ( s.isEmpty() )
return QStringList();
else
return QStringList::split( sep, s );
}
void Config::clearGroup()
{
if ( git == groups.end() ) {
qWarning( "no group set" );
return;
}
( *git ).clear();
}
void Config::write( const QString &fn )
{
if ( !fn.isEmpty() )
filename = fn;
QFile f( filename );
if ( !f.open( IO_WriteOnly ) ) {
qWarning( "could not open for writing `%s'", filename.latin1() );
git = groups.end();
return;
}
QTextStream s( &f );
QMap< QString, ConfigGroup >::Iterator g_it = groups.begin();
for ( ; g_it != groups.end(); ++g_it ) {
s << "[" << g_it.key() << "]" << "\n";
ConfigGroup::Iterator e_it = ( *g_it ).begin();
for ( ; e_it != ( *g_it ).end(); ++e_it )
s << e_it.key() << " = " << *e_it << "\n";
}
f.close();
}
void Config::read()
{
if ( !QFileInfo( filename ).exists() ) {
// qWarning( "`%s' doesn't exist", filename.latin1() );
git = groups.end();
return;
}
QFile f( filename );
if ( !f.open( IO_ReadOnly ) ) {
qWarning( "could not open for reading `%s'", filename.latin1() );
git = groups.end();
return;
}
QTextStream s( &f );
QString line;
while ( !s.atEnd() ) {
line = s.readLine();
parse( line );
}
f.close();
}
void Config::parse( const QString &l )
{
QString line = l.stripWhiteSpace();
if ( line[ 0 ] == QChar( '[' ) ) {
QString gname = line;
gname = gname.remove( 0, 1 );
if ( gname[ (int)gname.length() - 1 ] == QChar( ']' ) )
gname = gname.remove( gname.length() - 1, 1 );
ConfigGroup *grp = new ConfigGroup;
git = groups.insert( gname, *grp );
} else {
if ( git == groups.end() ) {
qWarning( "line `%s' out of group", line.latin1() );
return;
}
QStringList lst = QStringList::split( '=', line );
if ( lst.count() != 2 && line.find( '=' ) == -1 ) {
qWarning( "corrupted line `%s' in group `%s'",
line.latin1(), git.key().latin1() );
return;
}
( *git ).insert( lst[ 0 ].stripWhiteSpace(), lst[ 1 ].stripWhiteSpace() );
}
}