代码行统计工具(C#)

来源:互联网 发布:改图软件app 编辑:程序博客网 时间:2024/06/06 04:54

开发环境介绍:
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))//使用指定路径、创建模式和读写权限初始化实例(创建文件流)            {                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);     }
0 0
原创粉丝点击