代碼統(tǒng)計工具1.1版本技術(shù)文檔
說明:主要記錄自己在做這個項(xiàng)目的過程中用到的方法和相關(guān)技術(shù)
1. 首先面臨的問題就是怎樣選擇一個目錄,網(wǎng)上搜索了一下,下面是解決方案(用到目錄對話框)
(1) 從默認(rèn)的磁盤總目錄下開始選擇:
TCHARszPath[MAX_PATH];
BROWSEINFObr;
ITEMIDLIST*pItem;
br.hwndOwner=this->GetSafeHwnd();
br.pidlRoot=0;
br.pszDisplayName=0;
br.lpszTitle=" 選擇路徑 ";
br.ulFlags=BIF_STATUSTEXT;
br.lpfn=0;
br.iImage=0;
br.lParam=0;
pItem=SHBrowseForFolder(&br);
if(pItem!=NULL)
{
if(SHGetPathFromIDList(pItem,szPath)==TRUE)
{
// 這就是我們得到的目錄名稱
CStringstrDir=szPath;
}
}
(2) 自己 設(shè)定需要目錄對話框默認(rèn)選擇的目錄
第一步:(和第一種不同的是需要為這個目錄對話框設(shè)定自定義回調(diào)函數(shù))
TCHARszDefaultDir[MAX_PATH];
CStringstrDef(_T("d://C++//"));// 需要設(shè)定的默認(rèn)的目錄
memcpy(szDefaultDir,strDef.GetBuffer(strDef.GetLength()),strDef.GetLength());
strDef.ReleaseBuffer();
TCHARszPath[MAX_PATH];
BROWSEINFObr;
ITEMIDLIST*pItem;
br.hwndOwner=this->GetSafeHwnd();
br.pidlRoot=0;
br.pszDisplayName=0;
br.lpszTitle=" 選擇路徑 ";
br.ulFlags=BIF_STATUSTEXT;
// 設(shè)置 CALLBACK 函數(shù)
br.lpfn=FA_BrowseCallbackProc;
br.iImage=0;
// 設(shè)置默認(rèn)路徑
br.lParam=long(&szDefaultDir);
/* 說明:在 Unicode 環(huán)境下,編譯測試,此處的默認(rèn)路徑無法起作用
/* 需要手動轉(zhuǎn)換成 TChar/WChar
/*TCharstrBuffer[MAX_PATH];
/*wcscpy(strBuffer,szDefaultDir);*/
pItem=SHBrowseForFolder(&br);
if(pItem!=NULL)
{
if(SHGetPathFromIDList(pItem,szPath)==TRUE)
{
// 這就是我們得到的目錄名稱
m_strDirPath=szPath;
}
}
第二步:設(shè)計回調(diào)函數(shù)
intCALLBACKFA_BrowseCallbackProc(HWNDhwnd,UINTuMsg,LPARAMlParam,LPARAMlpData)
{
switch(uMsg)
{
caseBFFM_INITIALIZED:// 初始化消息
// 傳遞默認(rèn)打開路徑(方法一)
//::SendMessage(hwnd,BFFM_SETSELECTION,TRUE,(LPARAM)"C://ProgramFiles");
// 傳遞默認(rèn)打開路徑(方法二,前提是 lpData 提前設(shè)置好)
::SendMessage(hwnd,BFFM_SETSELECTION,TRUE,lpData);
break;
caseBFFM_SELCHANGED:// 選擇路徑變化,
{
charcurr[MAX_PATH];
SHGetPathFromIDList((LPCITEMIDLIST)lParam,curr);
::SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)curr);
}
break;
default:
break;
}
return0;
}
(3) 用到 的數(shù)據(jù)結(jié)構(gòu)( MSDN 查看相應(yīng)介紹):
typedefstruct_browseinfo{
HWNDhwndOwner;
LPCITEMIDLISTpidlRoot;
LPTSTRpszDisplayName;
LPCTSTRlpszTitle;
UINTulFlags;
BFFCALLBACKlpfn;
LPARAMlParam;
intiImage;
}BROWSEINFO,*PBROWSEINFO,*LPBROWSEINFO;
typedefstruct_ITEMIDLIST{
SHITEMIDmkid;
}ITEMIDLIST,*LPITEMIDLIST;
typedefconstITEMIDLIST*LPCITEMIDLIST;
2. 遍歷一個目錄(需要遞歸遍歷下面所有的文件)并保存源代碼文件的文件名(后 綴名為 .c,cpp,.h,.java)
/********************************************************************
* 函數(shù)名 :
FA_ReadDirectory(CStringstrDirPath)
* 函數(shù)功能 :
讀取一個目錄下的所有文件
* 輸入?yún)?shù) :
strDirPath: 目錄的完整路徑
* 輸出參數(shù) :
* 返回值 :
* 用到的全局變量和結(jié)構(gòu) :
* 其他說明 :
********************************************************************/
voidCFA_CodeAnalysisView::FA_ReadDirectory(CStringstrDirPath)
{
WIN32_FIND_DATAtFind={0};
CStringstrTemp;
CStringstrDirTemp;
CStringstrSuffix;
strDirPath.Format("%s//*",strDirPath);
HANDLEhSearch=::FindFirstFile(strDirPath,&tFind);
if(hSearch==INVALID_HANDLE_VALUE)
{
return;
}
// 過濾掉 . 和 .. 文件目錄
::FindNextFile(hSearch,&tFind);
while(::FindNextFile(hSearch,&tFind))
{
strDirTemp=strDirPath;
strTemp.Format("%s",tFind.cFileName);
// 去掉最后那一個 * 通配符
strDirTemp=strDirTemp.Left(strDirTemp.GetLength()-1);
strDirTemp+=strTemp;
if((tFind.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)!=0)
{
FA_ReadDirectory(strDirTemp);
}
strSuffix=strTemp.Right(strTemp.GetLength()-strTemp.Find('.'));
if(!strSuffix.CompareNoCase(".h")||!strSuffix.CompareNoCase(".cpp")||
!strSuffix.CompareNoCase(".c")||!strSuffix.CompareNoCase(".java"))
{
m_strFileName[m_iFileCount]=strDirTemp;
m_iFileCount++;
}
}
::FindClose(hSearch);
}
知識點(diǎn): FindFirstFile 和 FindNextFile 函數(shù)以及下面這個結(jié)構(gòu)體 .
typedefstruct_WIN32_FIND_DATA{
DWORD dwFileAttributes ;
FILETIME ftCreationTime ;
FILETIME f tLastAccessTime ;
FILETIME ftLastWriteTime ;
DWORD nFileSizeHigh ;
DWORD nFileSizeLow ;
DWORD dwOID ;
TCHAR cFileName [MAX_PATH] ;
}WIN32_FIND_DATA;
3. 計算
/********************************************************************
* 函數(shù)名 :
FA_CalculateLines()
* 函數(shù)功能 :
計算各個文件的代碼行數(shù),注釋函數(shù)以及空白函數(shù)
* 輸入?yún)?shù) :
* 輸出參數(shù) :
* 返回值 :
* 用到的全局變量和結(jié)構(gòu) :
* 其他說明 :
********************************************************************/
voidCFA_CodeAnalysisView::FA_CalculateLines()
{
m_lBlankTotalLines=0;
m_lNoteTotalLines=0;
m_lCodeTotalLines=0;
CStringstrFileName;
CStringstrRecvData;
CStdioFilefile;
BOOLbNoteEnd=FALSE;
intblankLines=0;
intnoteLines=0;
intcodeLines=0;
intblankTotalLines=0;
intnoteTotalLines=0;
intcodeTotalLines=0;
CRectrt;
GetClientRect(rt);
intiAverHigh=rt.Height()/32;
/************************************************************************/
/* 以下代碼段計算每個文件的有效代碼行數(shù),注釋行數(shù)以及空行數(shù)
/* 計算所有文件的總的相對應(yīng)的行數(shù)
/* 用的是一個從 CFile 繼承的類 CStdioFile ,因?yàn)樗幸粋€方法可以直接讀一行文件
/* 內(nèi)容到一個 CString 中
/************************************************************************/
for(inti=0;i<m_iFileCount;i++)
{
strFileName=m_strFileName[i];
// 以只讀模式打開文件
file.Open(strFileName,CFile::modeRead);
// 讀入一行帶字符串中
while(file.ReadString(strRecvData))
{
// 判斷是否是多行注釋的開頭
if(!strRecvData.Left(2).Compare("/*")&&!bNoteEnd)
{
// 判斷多行注釋是否在當(dāng)前行的結(jié)束
if(strRecvData.Right(2).Compare("*/"))
{
bNoteEnd=TRUE;
}
noteLines++;
}
// 判斷是不是多行注釋的結(jié)束
elseif(!strRecvData.Right(2).Compare("*/")&&bNoteEnd)
{
noteLines++;
bNoteEnd=FALSE;
}
// 判斷當(dāng)前行在多行注釋中間部分
elseif(bNoteEnd)
{
noteLines++;
}
// 判斷是否是空行
elseif(strRecvData.TrimLeft("/t"),strRecvData.IsEmpty())
{
blankLines++;
}
// 判斷是否是單行注釋
elseif(!strRecvData.Left(2).Compare("http://"))
{
noteLines++;
}
// 否則是有效代碼行
else
{
codeLines++;
}
}
// 注意用完一個文件后關(guān)閉
file.Close();
m_iBlankLines[i]=blankLines;
m_iNoteLines[i]=noteLines;
m_iCodeLines[i]=codeLines;
m_lBlankTotalLines+=blankLines;
m_lNoteTotalLines+=noteLines;
m_lCodeTotalLines+=codeLines;
blankLines=0;
noteLines=0;
codeLines=0;
}
// 根據(jù)計算結(jié)果計算視圖總共的高度
if(m_iFileCount>7)
{
CSizesizeTotal;
sizeTotal.cx=600;
sizeTotal.cy=m_iFileCount*iAverHigh*4;
SetScrollSizes(MM_TEXT,sizeTotal);
}
}
知識點(diǎn): CStdioFile 類的使用以及它的函數(shù) ReadStirng 讀入文件的一行到一個字符串
4. 輸出計算結(jié)果:
/********************************************************************
* 函數(shù)名 :
DrawFileText(CDC*pDC)
* 函數(shù)功能 :
輸出文件名,及各個計算結(jié)果
* 輸入?yún)?shù) :
pDC: 用于輸出文字的 CDC 指針
* 輸出參數(shù) :
* 返回值 :
* 用到的全局變量和結(jié)構(gòu) :
* 其他說明 :
********************************************************************/
voidCFA_CodeAnalysisView::FA_DrawFileText(CDC*pDC)
{
CStringstrFileName;
pDC->SetBkMode(TRANSPARENT);
CRectrt;
GetClientRect(rt);
intiAverHigh=rt.Height()/32;
pDC->SetTextColor(RGB(0,0,0));
strFileName.Format(" 此目錄下各個行數(shù)的總數(shù)如下 ( 總共有 %d 個文件 ) : ",m_iFileCount);
pDC->DrawText(strFileName,CRect(0,0,rt.Width(),20),DT_LEFT);
pDC->SetTextColor(RGB(255,0,0));
strFileName.Format(" 總代碼有 %d 行 ",m_lCodeTotalLines);
pDC->DrawText(strFileName,CRect(50,1*iAverHigh,rt.Width(),1*iAverHigh+20),DT_LEFT);
pDC->SetTextColor(RGB(0,255,0));
strFileName.Format(" 總注釋有 %d 行 ",m_lNoteTotalLines);
pDC->DrawText(strFileName,CRect(50,2*iAverHigh,rt.Width(),2*iAverHigh+20),DT_LEFT);
pDC->SetTextColor(RGB(0,0,255));
strFileName.Format(" 總空行有 %d 行 ",m_lBlankTotalLines);
pDC->DrawText(strFileName,CRect(50,3*iAverHigh,rt.Width(),3*iAverHigh+20),DT_LEFT);
for(inti=0;i<m_iFileCount;i++)
{
strFileName=m_strFileName[i];
pDC->SetTextColor(RGB(0,0,0));
pDC->DrawText(strFileName.Right(strFileName.GetLength()-m_strDirPath.GetLength()-1),
CRect(0,(i+1)*4*iAverHigh,rt.Width(),(i+1)*4*iAverHigh+20),DT_LEFT);
pDC->SetTextColor(RGB(255,0,0));
strFileName.Format(" 代碼有 %d 行 ",m_iCodeLines[i]);
pDC->DrawText(strFileName,CRect(50,((i+1)*4+1)*iAverHigh,rt.Width(),
((i+1)*4+1)*iAverHigh+20),DT_LEFT);
pDC->SetTextColor(RGB(0,255,0));
strFileName.Format(" 注釋有 %d 行 ",m_iNoteLines[i]);
pDC->DrawText(strFileName,CRect(50,((i+1)*4+2)*iAverHigh,rt.Width(),
((i+1)*4+2)*iAverHigh+20),DT_LEFT);
pDC->SetTextColor(RGB(0,0,255));
strFileName.Format(" 空行有 %d 行 ",m_iBlankLines[i]);
pDC->DrawText(strFileName,CRect(50,((i+1)*4+3)*iAverHigh,rt.Width(),
((i+1)*4+3)*iAverHigh+20),DT_LEFT);
}
}
5. 運(yùn)行效果
6. 總結(jié)
此項(xiàng)目雖然很小,但是比較實(shí)用,我們可以簡單的計算一個目錄下或是一個工程有多少代碼行,注釋行以及空白行。對于自己編程多少的檢驗(yàn),以及一個團(tuán)隊(duì)內(nèi)每個成員的編程多少做統(tǒng)計。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
