同一問題的兩種不同解法 : MFC8.0 與 C++ 標準庫

前兩天寫了一個對40M的有格式文本文件的信息抽取,開始使用 MFC的CFile來讀取,存儲到char*中,然後對每個字符循環讀取,判斷抽取有用信息.思路很簡單,也很笨拙,所以也就沒有奢望它的效率好到那裏.但實際運行的時候還是非常令人吃驚,兩個多小時竟然沒有跑完; 又細看了一下代碼,只做簡單的優化是沒有用處了,就改用了C++來重新寫,fstream的標準庫,string 做爲buffer,又調用了string的一些方法,結果非常的好,用了30多秒,就跑完了. 現把代碼貼出來 ,達人多指教.

文本文件是按行組織的,每一行的數據以空格分割,共44維數據,每一維是 Key:value的格式.現在要取出其中的 qid,1,13...等幾維數據,每行的前後的信息也要保留.
0 qid:1 1:11.512826 2:288.000000 3:195.000000 4:6.000000 5:2.000000 6:0.223063 7:0.000858 8:0.000677 9:0.000018 10:0.000826 11:0.001129 12:0.003413 13:10.546871 14:0.000772 15:-14.725600 16:0.017391 17:-12.865100 18:-9.148330 19:-8.108850 20:0.569967 21:-8.119490 22:-7.974970 23:-7.379150 24:1.563410 25:-7.253540 26:-7.252590 27:10.546905 28:2.000000 29:0.000000 30:0.000000 31:0.000000 32:0.000035 33:0.000000 34:0.000000 35:0.000000 36:0.000249 37:0.143097 38:0.000607 39:0.004101 40:0.001772 41:0.001124 42:19.575701 43:12.622301 44:11.723003 #docid = 1032

第一種寫法:
CExtractKeysDlg::CExtractKeysDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CExtractKeysDlg::IDD, pParent)
    , openfileedit(_T(
""))
    , savefileedit(_T(
""))
    , saveDim(_T(
""))
{
    m_hIcon 
= AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    openfileedit
="d:/d.txt";
    savefileedit
="d:/e.txt";
    saveDim
="qid,1,13,27,28,39,40,41,42,43,44";
    
//UpdateData(false);

}


void CExtractKeysDlg::OnBnClickedExtract()

{
    
// TODO: 在此添加控件通知處理程序代碼
    const int readlen=1024*64//讀取64k大的文件
    char buf[readlen],wbuf[readlen];
    
int truelen(0),wlen(0);
    
int wflag(1);//記錄需要寫入幾次的標誌
    UpdateData(true);
    CFile cfopen(
this->openfileedit,CFile::modeRead);
    CFile cfsave(
this->savefileedit,CFile::modeCreate|CFile::modeWrite);
    
    
do{
        truelen
=cfopen.Read(buf,readlen);
        
int i(0),wbegin(0),wend(0),lastspace(0),wlast(0);

        
for(;i<truelen;i++){
            
switch(buf[i]){
                
case ' ':                       //記錄空格位置,完成寫任務
                    lastspace=i;
                    
if(wflag){
                        wflag
--;
                        wend
=lastspace-1;
                        ArrayPut(buf,wbuf,wbegin,wend,wlast);
                        
if (wflag) wbegin=i;

                    }

                    
break;
                
case ':':                  //檢測,置寫標記
                    if (IsIn(buf,lastspace+1,i-1)){
                        wflag
++;
                        wbegin
=lastspace;
                    }

                    
break;
                
case 10:                    //換行之前的要寫入
                    if(wflag){

                        wend
=i;
                        ArrayPut(buf,wbuf,wbegin,wend,wlast);
                        wbegin
=i+1;

                    }

                    
break;
                
case '#':                    //docid默認寫入
                    wflag += 3;
                    wbegin
=i-1;
                    
break;

            }
//switch
        }
//for
        if(wflag && wend>=wbegin) ArrayPut(buf,wbuf,wbegin,wend,wlast);
        
if(!wflag){
            
            cfopen.Seek(lastspace
-truelen,CFile::current);
        }

        cfsave.Write(wbuf,wlast);
        
//cfsave.Flush(); //先在內存中緩存,到一定數量再到文件中.
    }
while(truelen==readlen);
    cfopen.Close();
    cfsave.Close();
//優化二,把幾個小函數聲明爲內聯函數,減小運行代價.
}


inline 
bool CExtractKeysDlg::ArrayPut(const char* src,char * dst,int begin,int end,int &lastpos)
{
    
//return false;
    for(;begin<=end;begin++)
        dst[lastpos
++]=src[begin];
    
return true;
}

inline 
bool CExtractKeysDlg::IsIn(const char* buf,int begin,int end)
{
    CString substr(
',');
    saveDim.Insert(
0,',');
    saveDim.AppendChar(
',');
    
int sub(1);
    
for(;begin<=end;begin++)
        substr.AppendChar(buf[begin]);
    substr.AppendChar(
',');
    
if (saveDim.Find(substr)<0)
        
return false;
    
else
        
return true;
}

第二種寫法:

#include 
"stdafx.h"
#include 
<fstream>
#include 
<vector>
#include 
<algorithm>
#include 
<string>
#include 
<sstream>
using namespace std;
/*---------------------------------------------------------------------------
                進取維數部分
-----------------------------------------------------------------------------
*/

const string token(",1,qid,13,27,28,39,40,41,42,43,44,");
const int NUM=15;
//qid,1,13,27,28,39,40,41,42,43,44
inline bool IsIn(string sbuf){
    sbuf.push_back(
',');
    sbuf.insert(
0,",");
    
if (token.find(sbuf)!=string::npos)
        
return true;
    
else
        
return false;

}

/*
name:Extracotr
function:從原始數據中提到指定的幾維
提取的維數定義在 token中
*/

void Extractor(){
    
string ifile("d:/TD2003.txt");
    cout 
<< "please input file to extract:"<<endl;
    
//cin>>ifile;
    ifstream infile(ifile.c_str() );
    
string ofile("d:/TD03.txt");
    cout
<<"please input the file to save as:"<<endl;
    
//cin>>ofile;
    ofstream outfile(ofile.c_str());
    
string buf,sbuf;
    
//while(getline(infile,buf,' ')){
    
//    outfile<<' ';
    
//}
    int enter(1);
    
string::size_type pos;
    
while( infile>>buf ){
        pos
=buf.find(':');
        
if (pos==string::npos)            
            outfile
<<buf<<(enter++ % NUM? " ":" ");
        
else
        
{
            
//buf.copy(sbuf,pos);
            sbuf=buf.substr(0,pos);
            
if (IsIn(sbuf))
                outfile
<<buf<<(enter++ % NUM? " ":" ");
        }

    }

    infile.close();
    outfile.close();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章