代码统计工具1.1版本技术文档

系统 1629 0

代码统计工具1.1版本技术文档

说明:主要记录自己在做这个项目的过程中用到的方法和相关技术

1. 首先面临的问题就是怎样选择一个目录,网上搜索了一下,下面是解决方案(用到目录对话框)

(1) 从默认的磁盘总目录下开始选择:

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) 自己 设定需要目录对话框默认选择的目录

第一步:(和第一种不同的是需要为这个目录对话框设定自定义回调函数)

TCHARszDefaultDir[MAX_PATH];

CStringstrDef(_T("d://C++//"));// 需要设定的默认的目录

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;

// 设置 CALLBACK 函数

br.lpfn=FA_BrowseCallbackProc;

br.iImage=0;

// 设置默认路径

br.lParam=long(&szDefaultDir);

/* 说明:在 Unicode 环境下,编译测试,此处的默认路径无法起作用

/* 需要手动转换成 TChar/WChar

/*TCharstrBuffer[MAX_PATH];

/*wcscpy(strBuffer,szDefaultDir);*/

pItem=SHBrowseForFolder(&br);

if(pItem!=NULL)

{

if(SHGetPathFromIDList(pItem,szPath)==TRUE)

{

// 这就是我们得到的目录名称

m_strDirPath=szPath;

}

}

第二步:设计回调函数

intCALLBACKFA_BrowseCallbackProc(HWNDhwnd,UINTuMsg,LPARAMlParam,LPARAMlpData)

{

switch(uMsg)

{

caseBFFM_INITIALIZED:// 初始化消息

// 传递默认打开路径(方法一)

//::SendMessage(hwnd,BFFM_SETSELECTION,TRUE,(LPARAM)"C://ProgramFiles");

// 传递默认打开路径(方法二,前提是 lpData 提前设置好)

::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) 用到 的数据结构( MSDN 查看相应介绍):

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)

/********************************************************************

* 函数名 :

FA_ReadDirectory(CStringstrDirPath)

* 函数功能 :

读取一个目录下的所有文件

* 输入参数 :

strDirPath: 目录的完整路径

* 输出参数 :

* 返回值 :

* 用到的全局变量和结构 :

* 其他说明 :

********************************************************************/

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);

}

知识点: FindFirstFile FindNextFile 函数以及下面这个结构体 .

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. 计算

/********************************************************************

* 函数名 :

FA_CalculateLines()

* 函数功能 :

计算各个文件的代码行数,注释函数以及空白函数

* 输入参数 :

* 输出参数 :

* 返回值 :

* 用到的全局变量和结构 :

* 其他说明 :

********************************************************************/

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;

/************************************************************************/

/* 以下代码段计算每个文件的有效代码行数,注释行数以及空行数

/* 计算所有文件的总的相对应的行数

/* 用的是一个从 CFile 继承的类 CStdioFile ,因为它有一个方法可以直接读一行文件

/* 内容到一个 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)

{

// 判断多行注释是否在当前行的结束

if(strRecvData.Right(2).Compare("*/"))

{

bNoteEnd=TRUE;

}

noteLines++;

}

// 判断是不是多行注释的结束

elseif(!strRecvData.Right(2).Compare("*/")&&bNoteEnd)

{

noteLines++;

bNoteEnd=FALSE;

}

// 判断当前行在多行注释中间部分

elseif(bNoteEnd)

{

noteLines++;

}

// 判断是否是空行

elseif(strRecvData.TrimLeft("/t"),strRecvData.IsEmpty())

{

blankLines++;

}

// 判断是否是单行注释

elseif(!strRecvData.Left(2).Compare("//"))

{

noteLines++;

}

// 否则是有效代码行

else

{

codeLines++;

}

}

// 注意用完一个文件后关闭

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;

}

// 根据计算结果计算视图总共的高度

if(m_iFileCount>7)

{

CSizesizeTotal;

sizeTotal.cx=600;

sizeTotal.cy=m_iFileCount*iAverHigh*4;

SetScrollSizes(MM_TEXT,sizeTotal);

}

}

知识点: CStdioFile 类的使用以及它的函数 ReadStirng 读入文件的一行到一个字符串

4. 输出计算结果:

/********************************************************************

* 函数名 :

DrawFileText(CDC*pDC)

* 函数功能 :

输出文件名,及各个计算结果

* 输入参数 :

pDC: 用于输出文字的 CDC 指针

* 输出参数 :

* 返回值 :

* 用到的全局变量和结构 :

* 其他说明 :

********************************************************************/

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(" 此目录下各个行数的总数如下 ( 总共有 %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. 运行效果

6. 总结

此项目虽然很小,但是比较实用,我们可以简单的计算一个目录下或是一个工程有多少代码行,注释行以及空白行。对于自己编程多少的检验,以及一个团队内每个成员的编程多少做统计。

<!--EndFragment-->

代码统计工具1.1版本技术文档


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论