您的位置:首页 > 编程语言 > C#

4000 代码行统计工具(C#)

2016-03-15 20:53 543 查看
开发环境介绍:

VS2013下的Windows窗体应用程序,程序运行时的初始界面如下:



操作步骤:

(1)选择操作系统下的某个文件目录,可以是文件夹目录,也可以是文件目录

(2)几点约束:

是否统计子文件夹里的文件的代码行数;

给定想要统计的代码文件的扩展名,即后缀名;

自定义排除统计某些行(匹配正则表达式);

(3)点击“开始统计”

(4)将统计结果(展示在DataGridView中)导出到EXCEL中

知识点深究:

(1)类的构造

首先展示本例中的一个类

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;

namespace CodeLineStatistics.Lib
{
/// <summary>
///封装文件的代码行数的统计信息的类
/// </summary>

public  class CodeFileCounter
{
//私有字段
private string filePath;
private string customExcludePattern;
private bool notContainEmpty;
private int emptyLineCount=0;
private int customExcludeLineCount=0;
private int singleCommentLineCount=0;
private int multiCommentLineCount=0;
private int codeLineCount=0;
private int totalCount=0;
private string[] lines;

private bool  isCalculated = false;//默认为false

//构造函数(带参)
/// <summary>
/// 构造一个统计代码文件的对象(其参数应该是应用程序接口传入的值,如文件夹路径,自定义排除模式,不统计空行)
/// </summary>
/// <param name="filePath">单个文件的路径</param>
/// <param name="customExcludePattern">自定义排除模式</param>
/// <param name="notContainEmpty">不统计空行</param>
public CodeFileCounter(string codeFilePath,string customExclusions,bool EmptyNotContained)
{
this.filePath = codeFilePath;
this.customExcludePattern=customExclusions.Replace("\r\n", "|").Replace("\n", "|");
this.notContainEmpty = EmptyNotContained;
}

//只读属性
public String FilePath //文件的虚拟路径
{
get
{
return filePath;
}
}
public String CustomExcludePattern //自定义排除模式
{
get
{
return customExcludePattern;
}
}
public Boolean NotContainEmpty //是否不包含空行
{
get
{
return notContainEmpty;
}

}
public Int32 EmptyLineCount//空白行
{
get
{
EnsureCalculate();
return emptyLineCount;
}
}
public Int32 CustomExcludeLineCount//自定义排除行,象引用行
{
get
{
EnsureCalculate();
return customExcludeLineCount;
}
}
public Int32 SingleCommentLineCount //单行注释行
{
get
{
EnsureCalculate();
return singleCommentLineCount;
}
}
public Int32 MultiCommentLineCount //多行注释行
{
get
{
EnsureCalculate();
return multiCommentLineCount;
}
}
public Int32 CodeLineCount//代码行
{
get
{
return TotalCount - EmptyLineCount - SingleCommentLineCount - MultiCommentLineCount - CustomExcludeLineCount;
}
}
public Int32 TotalCount //总行数
{
get
{
return Lines.Length;
}
}
public string[] Lines
{
get
{
if (lines == null)
{
lines = GetFileLines(FilePath);
}
return lines;
}
}
//匹配单行注释  //.*
//匹配多行注释  /\*[\w\W]*?\*/

//   说明:
//    /\*: 注释开始时的 /*
//    [\w\W]*?: 用非贪婪模式匹配任意长度任意字符。(非贪婪模式指:尽可能少的去匹配,这时,后面的匹配结束部分的标识会尽可能早的起作用。)
//    \*/:匹配注释结束的*/

public void EnsureCalculate()
{
if (!isCalculated)//若没有计算过该行
{
Count();
isCalculated = true;
}
}
/// <summary>
///统计每个文件中的空白行、单行注释行、多行注释行、自定义排除行
/// </summary>
public void Count()
{
Regex EmptyLineReg=new Regex(@"^\s*$");//"\s"匹配任何空白字符,包括空白符、制表符、换页符等,“*”匹配前面的子表达式零次或者多次
Regex SingleCommentReg = new Regex(@"^//.*$");
Regex MultiCommentReg = new Regex(@"^/\*[\w\W]*?\*/$");
Regex CustomExcludeReg = new Regex(CustomExcludePattern);

this.emptyLineCount = 0;
this.singleCommentLineCount = 0;
this.multiCommentLineCount = 0;
this.customExcludeLineCount = 0;
foreach (var line in Lines)
{
if (NotContainEmpty && EmptyLineReg.IsMatch(line))//排除模式中“不包含空行”即要统计空行
{
emptyLineCount++;
}
else if (SingleCommentReg.IsMatch(line))
{
singleCommentLineCount++;
}
else if (MultiCommentReg.IsMatch(line))
{
multiCommentLineCount++;
}
else if (CustomExcludePattern.Length > 0 && CustomExcludeReg.IsMatch(line))
{
customExcludeLineCount++;
}
else //代码行
{
//CodeLineCount++;
}
}
}
/// <summary>
/// 获取一个指定路径的文件里的所有行
/// </summary>
/// <param name="filePath">文件路径</param>
/// <returns>字符串行数组</returns>
public  string[] GetFileLines(string filePath)
{
using (FileStream fs=new FileStream(filePath,FileMode.Open,FileAccess.Read
a5b2
))//使用指定路径、创建模式和读写权限初始化实例(创建文件流)
{
StreamReader sr = new StreamReader(fs, Encoding.Default);//用指定的编码为指定的流创建从字节中读取字符的对象
string[] lines=sr.ReadToEnd().Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);//返回空数组元素
return lines;
}
}

}
}


说明:

CodeFileCounter这个类的主要功能是:针对某个代码文件(文件路径,注意这里并非文件夹路径)的统计信息(空白行、单行注释行、多行注释行、自定义排除行、代码行、代码总行数)。

该类由三部分组成:字段、属性、方法。首先说字段,在C#中,我们可以非常自由的、毫无限制的访问公有字段,但在一些场合中,我们可能希望限制只能给字段赋于某个范围的值、或是要求字段只能读或只能写,或是在改变字段时能改变对象的其他一些状态,这些单靠字段是无法做到的。当然也有私有字段;然后说说属性,属性是类、结构或接口的命名成员,属性将类中的字段公开,通过属性的set和get访问器访问字段,它提供了一种抽象级别来允许您更改字段。set块负责属性的写入工作,get块负责属性的读取工作。在两个块中都可以做一些其他操作,如在set中验证赋的值是否符合要求并决定是否进行赋值。当缺少其中一块时属性就只能读或只能写,set和get块中属性必需有一个,因为即不能读又不能写的属性是没有意义的。

属性的组成: 私有字段(之所以是私有的是因为只能通过属性来赋值)、get访问器(读取数据,return字段值或者用于计算并返回字段值,还可以throw终止,可包含简单验证逻辑)、set访问器(给属性赋值,类似于一个返回void的方法)

属性的分类:按访问修饰符来分:public/private/protected/internal,定义类的用户如何才能访问属性;

(static)静态属性,实例属性,(virtual)虚属性,抽(abstract)象属性;

只读、只写、可读写属性;

属性和字段的区别

相同点:

都是类的成员,属性是类的属性,而字段是类的数据成员

不同点:

1 属性可进行数据绑定

2 属性可通过set和get方法进行数据安全性检验,而字段不行

3 属性可进行线程同步

public string Name

{

set{

lock(this)

{

}

}

}

4 属性可以是抽象的,而字段不行

5 属性可以接口的形式表现

6 基于属性的索引

7 不要直接把字段转化为属性

8 字段在值的处理上并不是那么的灵活,给它赋什么它就是什么,不允许经过逻辑处理。如果把一个人的身高写成一个字段,给它赋值1000M,这显示是不正常的数据,字段无法处理这种特殊数据。

9 与字段不同,属性不作为变量来分类。因此,不能将属性作为 ref参数或 out参数传递。

10 通常属性的名称和它所访问的内部成员的名称相同,只不过首字母大写。且set服务器中使用的隐式参数value(该参数具有基础成员变量的类型);

最后说说方法,一个是构造函数,另一个是普通方法。若没有显示的构造函数,则系统会默认一个无参的构造函数(没有返回类型),这是有参构造函数的定义:public CodeFileCounter(string codeFilePath,string customExclusions,bool EmptyNotContained){},其中的形参是由应用程序提供实参,另一些方法规定类的操作。

(2)获取所有文件的统计信息

List<CodeFileCounter> codeFileCounterList = GetAllFilesStatistics(txtFilePath.Text, chkBoxIsContained.Checked, chkEmptyLine.Checked, txtSourceFileExtension.Text, txtExcludePattern.Text);


(3)将统计信息填充到DataGridView

FillToGrid(codeFileCounterList, txtFilePath.Text);


(4)将DataGridView里的数据导出到Excel中

private void btnExport_Click(object sender, EventArgs e)
{
SaveToExcel(gvShowDetail);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: