c++常用功能封裝

來源:互聯網
上載者:User

標籤:exp   補充   directory   ng2   全域   檔案流   tor   tput   代碼   

C++檔案讀寫的封裝

 

在C++開發中,檔案讀寫是很常用的功能,出於代碼複用的考慮,將它們進行封裝。

其中,預設讀寫的檔案是文字檔,並且需要按行處理。調用者只需要關注讀取出來的每一行的處理方式。寫檔案只是簡單的開關檔案流。

 

具體代碼如下:

 /**    * @brief    讀檔案      * @author   env0y    * @param    [in]const std::string& filename,檔案名稱(絕對路徑) [in]T& fn,對讀出的資料進行逐行操作的函數.fn(std::string,...)[in/out]std::map<std::string,int>& fieldIdx,表頭欄位及其索引值[in]const char Separator = ‘,‘,表頭欄位分隔符號,預設‘,‘    * @param    [out]none    * @return   bool    * @note     1. 參數fieldIdx帶入表頭欄位值,帶出欄位值對應的索引2. 參數fn的第一個參數必須是std::string類型    */template<typename T>static inline bool ReadFile(const std::string& filename, T& fn, std::map<std::string,int>& fieldIdx,const char Separator = ‘,‘ ){typedef std::map<std::string,int> FieldMap;ifstream fd(filename,std::ios::in);fd.imbue(std::locale(std::locale::empty(), new std::codecvt_utf8<wchar_t>));if (fd.fail()){//LOG_ERROR_F( ModuleInfo,_T("ReadFile:Open [%s] failure."),CString(filename.c_str()).GetString());return false;}auto Raii = [&](){ fd.close(); };ON_SCOPE_EXIT(Raii);//LOG_DEBUG_F( ModuleInfo,_T("ReadFile:file [%s] size [%lld] Bytes."),CString(filename.c_str()).GetString(),CalcFileSz(fd));std::string oneline;(void)getline(fd,oneline);if ( false == FieldIndexLookup(oneline,fieldIdx,Separator) ){return false;}do {(void)fn( oneline );  //每讀一行,傳遞給使用者定義的函數oneline.clear();(void)getline(fd,oneline);} while ( !fd.eof() );return true;}/*** @brief    欄位索引尋找確認  * @author   env0y [2015/12/24 11:09:49]* @param    [in]const std::string& tableHeader,表頭 [in/out]std::map<std::string,int>& fieldIdx,欄位為入參,索引為出參char separator = ‘,‘,表頭欄位分隔符號,預設為‘,‘* @param    [out]none* @return   bool,尋找是否成功* @note     none*/static inline bool FieldIndexLookup( const std::string& tableHeader,std::map<std::string,int>& fieldIdx,char separator /*= ‘,‘*/ ){if (fieldIdx.empty()){return true;}typedef std::map<std::string,int> FieldMap;const int  FieldNotExist = -1;(void)std::for_each( fieldIdx.begin(),fieldIdx.end(),[=](FieldMap::value_type& ele){ ele.second = FieldNotExist;});int TmpIdx = FieldNotExist;std::string subStr = tableHeader; string::size_type curpos = std::string::npos;do{curpos = subStr.find_first_of(separator);std::string fieldStr = subStr.substr(0,curpos);subStr = subStr.substr(curpos+1);++TmpIdx;auto it = fieldIdx.find( fieldStr );if ( it != fieldIdx.end()){it->second = TmpIdx;}} while ( std::string::npos != curpos );bool bFieldsInsufficient(false);//- 欄位是否缺失 (void)std::for_each(fieldIdx.begin(),fieldIdx.end(),[&](const FieldMap::value_type& ele){if ( ele.second == FieldNotExist ){bFieldsInsufficient = true;std::cout << "FieldIndex: Lack of field:" << ele.first.c_str() << "\n";//LOG_ERROR_F( ModuleInfo,_T("FieldIndex: Lack of field [%s]."),CString(ele.first.c_str()).GetString() );}});return (false == bFieldsInsufficient);}

  函數FiledIndexLookup用來尋找指定表頭是否存在於第一行檔案中。

 

寫檔案的代碼如下:

/*** @brief    計算檔案大小  * @author   env0y [2015/10/19 17:25:37]* @param    [in]fstream& fd,檔案描述符    * @param    [out]none* @return   unsigned __int64,檔案大小 單位位元組* @note     none*/template<typename FileStream>static inline unsigned __int64 CalcFileSz(FileStream& fd){(void)fd.seekg(0,ios::end);streampos uSz = fd.tellg();(void)fd.seekg(0,ios::beg);return (unsigned __int64)uSz;}  /**  * @brief    寫檔案    * @author   env0y [2015/10/19 9:14:33]  * @param    [in]const std::string& filename,要產生的檔案(絕對路徑)  [in]  T& fn,函數指標/成員函數/函數對象/仿函數/Lambda運算式  [in]int mode = std::ios::out,檔案操作模式,預設ios::out  [in]  const std::string & title = "",產生的檔案表頭,預設空  * @param    [out]none  * @return   bool  * @note     fn的參數(wofstream&,...)  */template<typename T>static inline bool WriteFile(const std::string& filename,T& fn,int mode = std::ios::out,const std::string & title = ""){(void)SHCreateDirectoryEx(nullptr, CString(filename.substr(0,filename.find_last_of("\\")).c_str()) ,nullptr);//LOG_DEBUG_F( ModuleInfo,_T("output [%s]."),CString(filename.c_str()).GetString());wofstream ofd(filename,mode);//ofd.imbue(std::locale(std::locale::empty(), new std::codecvt_utf8<wchar_t>));if( ofd.fail() ){//LOG_ERROR_F( ModuleInfo,_T("WriteFile:Open or Create [%s] failure."),CString(filename.c_str()).GetString());return false;}if( title.length() ){title.back() == ‘\n‘ ?ofd << title.c_str() :ofd << title.c_str() << "\n"; }(void)fn(ofd);ofd.close();return true;}template<typename T,size_t X>static inline bool WriteFile(const std::string(&filename)[X],T& fn,int mode = std::ios::out,const std::string & title = ""){std::wofstream arrofds[X];size_t ulCnt = 0;bool bRst = std::any_of(std::begin(filename),std::end(filename),[&](const std::string& name)->bool{(void)SHCreateDirectoryEx(nullptr, CString(name.substr(0,name.find_last_of("\\")).c_str()) ,nullptr);arrofds[ulCnt].open(name,mode);if( arrofds[ulCnt].fail() ){LOG_ERROR_F( ModuleInfo,_T("WriteFile:Open or Create [%s] failure."),CString(name.c_str()).GetString());return true;}arrofds[ulCnt++] << title.c_str();return false;});if (bRst){return false;}(void)fn(arrofds);std::for_each(std::begin(arrofds),std::end(arrofds),[](std::wofstream& fd){fd.close();});return true;}

  第一個是一次寫一個檔案,第二個是寫多個。

 

調用舉例如下:

bool COutputPDFGridULSINRFreqBand::LoadCurrentBHGridInfo(){CString CurrentBHGridInfoPath = JoinPath(m_prjPath, CString(_T("GridLevel\\Total\\CurrentBHGridInfo.csv")));m_FileHeadRel.emplace(std::make_pair("GridID",-1));m_FileHeadRel.emplace(std::make_pair("Longitude",-1));m_FileHeadRel.emplace(std::make_pair("Latitude",-1));m_FileHeadRel.emplace(std::make_pair("Site ID",-1));m_FileHeadRel.emplace(std::make_pair("Cell ID",-1));m_FileHeadRel.emplace(std::make_pair("FrequencyBand",-1));m_FileHeadRel.emplace(std::make_pair("BandNum",-1));m_FileHeadRel.emplace(std::make_pair("CellULSINR",-1));m_FileHeadRel.emplace(std::make_pair("CellPrivateUEMRNum",-1));return ReadFile(CString2String(CurrentBHGridInfoPath),std::bind(&COutputPDFGridULSINRFreqBand::ReadLine,this,std::placeholders::_1),m_FileHeadRel);}

 

第二個參數是模板參數,支援lambda運算式、c全域函數、c++成員函數等。

在實際項目中可以把它們封裝到一個命名空間,可以更安全方便的使用。 :)

 

除零保護也是c++經常做的事情,可以提取成如下函數:

/*** @brief    除法保護* @author   env0y* @param  [in] Dividend dividend : 分子  [in] Divisor divisor : 分母* @param  [out] none* @return : 如果分母為0(除數為0),返回0; 否則返回正常除數值*/template <typename Dividend,typename Divisor>static inline double DivisionProtection(Dividend dividend,Divisor divisor){double dResult(0.0);static const char* Integers[] = {"char","unsigned char","short","unsigned short","int","unsigned int","long","unsigned long","__int64","unsigned __int64","long long","unsigned long long"};static const char* Floats[] = {"float","double"};static const int iSz = _countof(Integers);static const int fSz = _countof(Floats);const char* typeDivisor = typeid(divisor).name();auto fCmp = [&](const char* str){ return 0 == strcmp(str,typeDivisor);};if ( (Floats+fSz) != std::find_if(Floats,Floats+fSz,fCmp) ){bool bIsZero = (fabs((double)divisor) < 1e-15 ) || (fabs((float)divisor) < 1e-6 );dResult = bIsZero ? 0.0 : dividend/divisor ;}else if ( (Integers+iSz) != std::find_if(Integers,Integers+iSz,fCmp) ){dResult = (0 == divisor) ? 0 : 1.0*dividend/divisor;}return dResult;}

  

而對浮點型數四捨五入函數則可以使用下面方法:

/*** @brief    根據所需精度四捨五入  * @author   env0y [2015/8/29]* @param    [in]const double& x,原始值[in]int precision,精度值* @param    [out]none* @return   double,四捨五入之後的值* @note     預設精度為1*/static inline double RoundByPrecision(const double& x, int precision/* = 1*/){if ( precision < 0 ){return x;}double temp = x * pow((double)10, precision);temp = floor(temp + 0.5);return (temp * pow((double)10, -precision));}

  

我們知道c++11已經有std::hash方法,那如何雜湊一個std::pair呢?

可以像下面這樣:

template <class T>inline void hash_combine(std::size_t & seed, const T & v){std::hash<T> hasher;seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);}namespace std{template<typename S, typename T> struct hash<pair<S, T>>{inline size_t operator()(const pair<S, T> & v) const{size_t seed = 0;::hash_combine(seed, v.first);::hash_combine(seed, v.second);return seed;}};


}

 

而像std::wstring和std::string之間的相互轉化,則可以:

static inline std::string ws2s( const std::wstring& wstr ){std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converterX;return converterX.to_bytes(wstr);}static inline std::wstring s2ws( const std::string& str ){std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converterX;return converterX.from_bytes(str);}

  

寫到這裡發現,讀檔案那裡用到了RAII,所以把宏定義補充如下:

class ScopeGuard{public:explicit ScopeGuard(std::function<void()> onExitScope):onExitScope_(onExitScope){};~ScopeGuard(){onExitScope_();};private:std::function<void()> onExitScope_;// noncopyableprivate: ScopeGuard(ScopeGuard const&);ScopeGuard& operator=(ScopeGuard const&);};/*lint -restore*/#define SCOPEGUARD_LINENAME_CAT(name, line) name##line#define SCOPEGUARD_LINENAME(name, line) SCOPEGUARD_LINENAME_CAT(name, line)//#define ON_SCOPE_EXIT(callback) ScopeGuard<decltype(callback)> SCOPEGUARD_LINENAME(EXIT, __LINE__)(callback)#define ON_SCOPE_EXIT(callback) ScopeGuard SCOPEGUARD_LINENAME(EXIT, __LINE__)(callback)

  

 

就這些。以後再補充吧!;)

 

c++常用功能封裝

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.