开发环境: vs2013, win10
经过很多次修改,和对一些错误的学习,才搞定了这么一个类:
比如说LPCTSTR的赋值,new和delete要成对出现,字符数组和字符串的库函数去取代自己写字符串处理函数等, wcsncpy_s用法,string类的赋值运算符等。
头文件:
/*
对文本的处理要求:'='号之前强制为整数,且只允许开头后者结尾存在空格(处理后丢弃空格),不允许存在非数字字符,否则将丢弃该键值对
=号右边的value原样保存,包括空格的存在.
对于读取多个ini文件,只要修改一下,就是在loadFile函数中不要对m_map进行clear
已通过的测试样例:
1 = abdfadfadfd
======
aaaaaa
vvvv
a
123 + 234
555=
zzz=
=dd
=123
=567=
========
a=1
1234adfdd
*/
#pragma once
#include "stdafx.h"
#include<iostream>
#include<fstream>
#include<windows.h>
#include<string>
#include<map>
class QueryIni
{
public:
QueryIni(){}
~QueryIni(){}
public:
/**
* @brief 初始化成员变量指针
* @return void
*/
static void Init();
/**
* @brief delete成员变量指针
* @return void
*/
static void UnInit();
public:
/**
* @brief 查找ini文件中的键值,必须先调用SetPath,传入路径,再调用GetValue;
* @param[in] const int iKey 要查询的键
* @return 查找成功返回value字符串,否则返回空字符串
*/
static std::wstring QueryIni::GetValue(const int iKey)
{
wchar_t sDes[MAX_PATH + 1] = { 0 };
QueryIni::_GetInstance()->_GetValue(iKey, sDes, MAX_PATH); //TRUE,得到查询结果
return sDes;
}
/**
* @brief 读取的文件路径
* @param[in] LPCTSTR pFilePath 读取的文件的路径
* @return 是否成功载入文件内的数据
*/
static bool LoadFile(LPCTSTR pFilePath);
/**
* @brief 清空map中的数据
*/
static void Clear();
private:
static QueryIni* _GetInstance();
bool QueryIni::_RemoveSpaceAndCheckNum(std::wstring &sKey);
bool _GetValue(const int iKey, wchar_t* sDes, const int len);
private:
std::map<int, std::wstring> m_map;
static QueryIni* ms_pInstance;
};
实现文件:
#include"stdafx.h"
#include"QueryIni.h"
#include <iostream>
#include <fstream>
#include <string>
#include <codecvt>
#include <locale>
#include<assert.h>
using namespace std;
QueryIni* QueryIni::ms_pInstance = NULL;
void QueryIni::Init()
{
if (ms_pInstance == NULL)
{
ms_pInstance = new QueryIni();
}
}
void QueryIni::UnInit()
{
if (ms_pInstance != NULL)
{
delete ms_pInstance;
ms_pInstance = NULL;
}
}
bool QueryIni::LoadFile(LPCTSTR pFilePath)
{
QueryIni* queryIni = QueryIni::_GetInstance();
if (pFilePath == NULL)
{
return false;
} //这个不一定要哦!
std::wifstream wFileStream(pFilePath, std::ios::binary);
if (wFileStream.is_open())
{
wchar_t buf[2] = {0};
wFileStream.read(buf, 2);
wFileStream.clear();
wFileStream.seekg(0, ios::beg);
bool isUnicode = (buf[0] == wchar_t(0xFF) && buf[1] == wchar_t(0xFE)) || (buf[0] == wchar_t(0xFE) && buf[1] == wchar_t(0xFF)) ;
assert(isUnicode == true);
// apply BOM-sensitive UTF-16 facet
wFileStream.imbue(std::locale(wFileStream.getloc(), new std::codecvt_utf16 < wchar_t, 0x10ffff, std::consume_header >));//第二个参数是此平面将读或写而不出错的wchar_t最大值
std::wstring wLine;
while (std::getline(wFileStream, wLine))
{
int equalPos = wLine.find_first_of(L'='); //从pos开始查找'='第一次出现的位置
std::wstring sKey = L"", sValue = L"";
if (equalPos != wstring::npos)
{
sKey = wLine.substr(0, equalPos);
sValue = wLine.substr(equalPos + 1, wLine.length() - equalPos);
if (queryIni->_RemoveSpaceAndCheckNum(sKey)) //键合法,插入map
{
int iKey = stoi(sKey);
queryIni->m_map.insert(make_pair(iKey, sValue));
}
}
}
wFileStream.close(); //打开完文件记得关闭
return true;
}
return false;
}
void QueryIni::Clear()
{
QueryIni::_GetInstance()->m_map.clear();
}
QueryIni* QueryIni::_GetInstance()
{
if (ms_pInstance == NULL)
{
ms_pInstance = new QueryIni();
}
return ms_pInstance;
}
bool QueryIni::_RemoveSpaceAndCheckNum(std::wstring &sKey)
{
sKey.erase(0, sKey.find_first_not_of(L" \t"));
sKey.erase(sKey.find_last_not_of(L" \t") + 1);
if (sKey == L"") //这是个空字符串
{
return false;
}
for (int i = 0; i < sKey.size(); i++)
{
if (sKey[i] > L'9' || sKey[i] < L'0')
{
return false;
}
}
return true;
}
bool QueryIni::_GetValue(const int iKey, wchar_t* sDes, const int len)
{
std::map<int, std::wstring>::iterator it = m_map.find(iKey);
if (it == m_map.end())
{
return false; //不存在
}
else
{
std::wstring sValue = it->second;
assert(sValue.length() < len); //小心长度溢出
wcsncpy_s(sDes, len, &(sValue[0]), sValue.length());
return true;
}
}
至于QueryIni::GetValue(const int iKey)函数为什么放在头文件而不是在实现文件中,参考: Windows跨模块内存管理的浅薄理解
使用的main函数:
#include "stdafx.h"
#include<iostream>
#include<fstream>
#include<windows.h>
#include<string>
#include<map>
#include <codecvt>
#include"QueryIni.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
QueryIni::Init();
QueryIni::LoadFile(L"C:\\Users\\admin\\Desktop\\test2.ini");
std::locale loc("chs");//windows下ok
std::wcout.imbue(loc);
std::wcout << QueryIni::GetValue(1) << std::endl;
std::wcout << QueryIni::GetValue(100152) << std::endl;
std::wcout << QueryIni::GetValue(102004) << std::endl;
std::wcout << QueryIni::GetValue(102054) << std::endl;
std::wcout << QueryIni::GetValue(100165) << std::endl;
QueryIni::UnInit();
{
return 0;
}