概述
开发环境介绍:
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("rn", "|").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;
}
}
//匹配单行注释
//.*
//匹配多行注释
/*[wW]*?*/
//
说明:
//
/*: 注释开始时的 /*
//
[wW]*?: 用非贪婪模式匹配任意长度任意字符。(非贪婪模式指:尽可能少的去匹配,这时,后面的匹配结束部分的标识会尽可能早的起作用。)
//
*/:匹配注释结束的*/
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(@"^/*[wW]*?*/$");
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))//使用指定路径、创建模式和读写权限初始化实例(创建文件流)
{
StreamReader sr = new StreamReader(fs, Encoding.Default);//用指定的编码为指定的流创建从字节中读取字符的对象
string[] lines=sr.ReadToEnd().Split(new string[] { "rn", "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);
}
最后
以上就是怡然啤酒为你收集整理的代码行统计工具(C#)的全部内容,希望文章能够帮你解决代码行统计工具(C#)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复