C++使用文字檔案進行引數配置
阿新 • • 發佈:2021-05-30
- 前言:程式中往往會配置一些引數,為了程式的靈活性,我們需要將引數在外部進行配置,在程式執行時進行解析並傳入程式中進行應用。
1. 常見的文字檔案配置
- 文字只是儲存檔案的一種形式,文字是儲存在本地磁碟中,不易於丟失,儲存一般是不常用的普通訊息,如果涉及到安全之類的資訊,可能需要儲存在資料庫,或者進行混淆加密。
- 常見的文字配置如下
[config]
name=mz
age=28
ismarried=false
tall=174.5
sex=man
[other]
technique=C++
- 將上述檔案儲存為conf.ini,在儲存的時候注意使用nodepad++開啟檢視該檔案結尾的行結束符是否正確,在window中和linux中行結束符不一致,有時候容易導致讀取失敗。下圖就是在最後一行未新增行結束符,有可能導致讀取該行配置失敗。
2. 相關程式碼
- config_ini.h
#ifndef CONFIGINI_H #define CONFIGINI_H #include<iostream> #include<fstream> #include<cstring> #include<string> #include<vector> #include<cstdlib> using namespace std; struct ConfigINIEntry{ ConfigINIEntry():isComment(false){} string index; string name; string value; string comment; bool isComment; }; class ConfigINI { public: ConfigINI(const char *fileName, bool autoCreate=false); void writeConfigFile(const char *fileName=NULL); ~ConfigINI(); /***********getter*************/ bool getBoolValue(const char* index, const char *name); int getIntValue(const char* index, const char *name); float getFloatValue(const char* index, const char *name); const char* getStringValue(const char* index, const char *name); /***********setter*************/ void setBoolValue(const char* index, const char *name, bool value); void setIntValue(const char* index, const char *name, int value); void setFloatValue(const char* index, const char *name, float value); void setStringValue(const char *index, const char* name, const char* value); /******* for test only *******/ void printAll(); /******* get all Entry *******/ vector<ConfigINIEntry> datas; private: char str[4096];//for temp string data void setStringValueWithIndex(const char *index, const char* name, const char* value); char iniFileName[4096]; char *data; const char (*lineData)[4096]; void loadConfigFile(); fstream *fStream; bool autoSave; bool autoCreate; }; #endif // CONFIGINI_H
- config_ini.cpp
include "config_ini.h"
#include <iostream>
#include <sstream>
#include <string>
#include <map>
#define CONFIGINI_DEBUG 0
#define log printf
#define mlog(msg, ...) do{\
if(CONFIGINI_DEBUG) printf(msg);\
}while(0)
ConfigINI::ConfigINI(const char *fileNameWithPath, bool _autoCreate):
data(NULL),
fStream(NULL),
autoSave(false),
autoCreate(_autoCreate)
{
strcpy(iniFileName, fileNameWithPath);
//std::cout << "INI Path:" << iniFileName << std::endl;
loadConfigFile();
}
void ConfigINI::loadConfigFile()
{
fstream fStream;
string p = iniFileName;
fStream.open(p,ios::in);
if(!fStream){
if(!autoCreate){
cout << "inifile [" << iniFileName << "] not found " << endl;
log("load config, file [%s] not exist", iniFileName);
}else{
log("inifile [%s] not found, create a new file", iniFileName);
}
return;
}else{
mlog("file open OK\n");
}
char line[4096];
char ch;
int i=0;
string index;
string str;
bool isComment=false;
while(!fStream.eof()){
fStream.read(&ch, 1);
ConfigINIEntry entry;
if(ch=='#' && i==0) isComment = true;
if(isComment==true && (ch=='\n' || ch=='\r')) {
isComment=false;
line[i++]='\0';
i=0;
entry.isComment = true;
entry.comment = line;
datas.push_back(entry);
}
if(isComment==true) {
line[i++]=ch;
continue;
}
//zfu: all up for comment
if(ch != '\n' || ch=='\r') line[i++]=ch;
else{
if(i==0) continue;
line[i]='\0';
str = string(line);
mlog("read one line {%s}", str.c_str());
if(line[0]=='['){
index = str;
}else{
entry.index = index.substr(1,index.length()-2);
int fIndex = str.find_first_of('=');
entry.name = str.substr(0,fIndex);
entry.value = str.substr(fIndex+1, str.length()-fIndex-1);
datas.push_back(entry);
mlog("entry: [email protected][%s]\t [email protected][%s]\t [email protected][%s]", entry.index.c_str(), entry.name.c_str(), entry.value.c_str());
}
i=0;
}
}
if(i!=0) {
ConfigINIEntry entry;
entry.index = str;
int fIndex = str.find_first_of('=');
entry.name = str.substr(0,fIndex);
entry.value = str.substr(fIndex+1, str.length()-fIndex-1);
datas.push_back(entry);
mlog("last add entry: [email protected][%s]\t [email protected][%s]\t [email protected][%s]", entry.index.c_str(), entry.name.c_str(), entry.value.c_str());
}
fStream.close();
}
ConfigINI::~ConfigINI()
{
if(autoSave){
cout<<"AUTO save Config file["<<iniFileName<<"]"<<endl;
writeConfigFile();
}
}
void ConfigINI::writeConfigFile(const char* fileName)
{
autoSave=false;
if(fileName==NULL) fileName = iniFileName;
fstream fStream;
fStream.open(fileName, ios_base::out | ios_base::trunc);
mlog("start write file[%s]", fileName);
string index = string("");
bool withComment = false;
bool isStart=true;
for(vector<ConfigINIEntry>::iterator it=datas.begin(); it!= datas.end(); it++){
ConfigINIEntry entry = *it;
if(entry.isComment) {
withComment=true;
if(isStart) fStream<<entry.comment.c_str()<<endl;
else fStream<<endl<<entry.comment.c_str()<<endl;
isStart=false;
mlog("write comment:%s", entry.comment.c_str());
continue;
}
if(strcmp(index.c_str(), entry.index.c_str()) != 0){
index = entry.index;
if(withComment || isStart) {
fStream<<'['<<entry.index<<']'<<endl;
withComment=false; isStart=false;
mlog("write index[%s]", entry.index.c_str());
}
else{
fStream<<endl<<'['<<entry.index<<']'<<endl;
mlog("write index [%s]", entry.index.c_str());
}
}
if (strlen(entry.name.c_str())==0 || strlen(entry.value.c_str())==0) {
mlog("skip invalid entry");
continue;
}
fStream<<entry.name<<'='<<entry.value<<endl;
mlog("write :%s=%s", entry.name.c_str(), entry.value.c_str());
}
fStream<<endl;
fStream.close();
mlog("write configfile[%s] end", fileName);
}
void ConfigINI::setStringValueWithIndex(const char *index, const char* name, const char* value)
{
autoSave = true;
ConfigINIEntry entry;
entry.index = index;
entry.name = name;
entry.value = value;
if(datas.size() == 0) {/*cout<<"data is NULL, push and return"<<endl; */
datas.push_back(entry);
return;
}
vector<ConfigINIEntry>::iterator it=datas.begin();
bool findIndex=false;
bool findName=false;
vector<ConfigINIEntry>::iterator itInsertPos;
for(it=datas.begin(); it!=datas.end(); it++){
if(findIndex==false){
if(strcmp(it->index.c_str(), index) == 0){
findIndex=true;
}
}
if(findIndex==true){
if(strcmp(it->index.c_str(), index) != 0){
break;
}else{
itInsertPos = it;
}
if(strcmp(it->name.c_str(), name)==0){
findName=true;
itInsertPos = it;
break;
}
continue;
}
itInsertPos=it;
}
if(findIndex && findName){
itInsertPos->value = string(value);
return;
}
datas.insert(++itInsertPos, 1, entry);
}
/***********getter*************/
bool ConfigINI::getBoolValue(const char* index, const char *name)
{
const char *str = getStringValue(index, name);
if(str == NULL)
{
cout << "not found ["<< index<<"] [" << name << "] in configuration file "<< endl;
log("not found [%s]-[%s] in configuration file ", index, name);
return false;
}
if(strcmp(str,"true") == 0) return true;
else return false;
}
int ConfigINI::getIntValue(const char *index, const char* name)
{
const char *str = getStringValue(index, name);
if(!str){
cout << "not found [" << index << "] [" << name << "] in configuration file " << endl;
return -1;
}else{
return atoi(str);
}
}
float ConfigINI::getFloatValue(const char* index, const char *name)
{
const char *str = getStringValue(index, name);
if(str == NULL)
{
cout << "not found [" << index << "] [" << name << "] in configuration file " << endl;
return -1.0;}
return atof(str);
}
const char* ConfigINI::getStringValue(const char* index, const char *name)
{
mlog("find index[%s]-name[%s]", index, name);
for(unsigned int i=0; i<datas.size(); i++){
if(strcmp(datas[i].index.c_str(), index) == 0){
mlog("find index[%s]", datas[i].index.c_str());
for(;i<datas.size();i++){
if(strcmp(datas[i].name.c_str(), name)==0)
return datas[i].value.c_str();
}
}
}
cout << "not found [" << index << "] [" << name << "] in configuration file " << endl;
//cout<<"DEBUG: ["<<index<<"] of--["<<name<<"] not found"<<endl;
return NULL;
}
/***********setter*************/
void ConfigINI::setBoolValue(const char* index, const char *name, bool value)
{
if(value) sprintf(str, "true");
else sprintf(str, "false");
setStringValueWithIndex(index,name,str);
}
void ConfigINI::setIntValue(const char* index, const char *name, int value)
{
sprintf(str, "%d", value);
setStringValueWithIndex(index,name,str);
}
void ConfigINI::setFloatValue(const char* index, const char *name, float value)
{
sprintf(str, "%f", value);
setStringValueWithIndex(index,name,str);
}
void ConfigINI::setStringValue(const char *index, const char* name, const char* value)
{
setStringValueWithIndex(index,name,value);
}
/*------------------------------------ for DEBUG ---------------------------------------*/
void ConfigINI::printAll()
{
log("List All Entry of INI File: [ %s ]\n", iniFileName);
for(vector<ConfigINIEntry>::iterator it=datas.begin(); it!= datas.end(); it++){
ConfigINIEntry entry = *it;
if(entry.isComment) {
//cout<<entry.comment<<endl;
continue;
}
log(" [%s]:\t\%s:\t\t%s\n", entry.index.c_str(), entry.name.c_str(), entry.value.c_str());
}
}
- main.cpp
#include "config_ini.h"
#include <iostream>
using namespace std;
int parseConfig(std::string &conf_fname)
{
const char *ini_path = conf_fname.c_str();
ConfigINI *ini = new ConfigINI(ini_path,false);
std::string excelPath("");
string name = ini->getStringValue("config", "name");
if (name.empty())
{
exit(-1);
}
int age = ini->getFloatValue("config", "age");
if (tmpTaskNum == -1)
{
exit(-1);
}
bool ismarried = ini->getBoolValue("config", "ismarried");
float tall = ini->getIntValue("config", "tall");
if (tall == -1)
{
exit(-1);
}
string technique = ini->getStringValue("other", "technique");
if (technique.empty())
{
exit(-1);
}
3. 總結
- 在配置檔案中儘量使用英文,而不是中文,在不同系統下不同的編碼可能導致亂碼問題產生,希望對大家有所幫助。