<转>统计源代码行数的一些实现方法
2015-05-13 23:01
218 查看
这个问题的思考其实对于某一种语言而言,基本都能实现,只是简单和复杂而已。而此次我讨论就是只是在linux下面使用了shell和c对源代码进行行 数的讨论。本打算是实现一个python版本的,由于python这块还不是太熟,所以就等以后熟了把这块补上。
前面是我们想要的内容,而后面的文件名却不是我们要得,怎么解决?一个思路就是将这个结果保存到一个文件中,然后使用
使用
find $1 -type f -maxdepth $2 -name "*.$3"
这边的
统计行数的核心就是如下的这个:
w =(wc -l $file | awk "{print $1}")
这边的file就是之前find的返回值,我们将上面的这个代码放在一个循环中。这边是awk的最简单使用了,将一个记录的第一个字段打印出来。但是不要混淆了这边的
加一些修饰
我们为了让输出变得好看一点,对echo的输出加一些修饰,主要是颜色的修饰:
好了,至此一个基本上能够满足要求的代码统计的脚本就完成了,一个完整的版本可以到我的gist看。
我们来看看如何实现C版本的统计程序?首先等解决的就是一个文件遍历的问题,这个解决不了接下去的工作就不用考虑。好在在linux中提供了一个 dirent.h的头文件,相关的函数都在这里面。我们可以用的是
readdir返回的是一个结构体,结构体中有一个参数d_name,这是保存的文件的名字,所以有了这个,我们就可以对其进行属性的判断了。因为我们要判断这是文件还是目录。
如何判断?没有shell中
这个函数是在
接着我们来考虑如何来遍历一个文件夹呢?首先的着肯定是在一个循环下。因为一个目录下有时不止一个文件,但是对于不同的目录的时候呢?例如一个目录下的一个子目录,如何去实现遍历?我们考虑到的是使用递归,递归调用我们写的那个函数。因为每次读取的目录只有一个。而且当
是时候统计代码了,我们剔除了目录的文件,剩下的就是真正的文件了。对于统计使用fgets来实现遍历一个文件,然后加个循环就解决问题。这边一个不好的就是没有办法去判断文件的类型,统计是对目录下所以的文件进行的统计,这一点不如shell的灵活。
下面是源代码,基本的思路就是这样,还要注意的一个细节是有两个特殊的目录就是
如果不提供参数,就遍历当前目录,提供了就统计给出的目录。
shell版
shell的强大快捷之处就在此体现出来了。我们使用find命令就直接能将目标的文件进行检索,然后我们就直接对检索出来的对象进行统计。统计 我们知道使用
wc这个命令,但是我们观察一下wc的输出:
206 ./2014-03-09-jekyll-blog.md
前面是我们想要的内容,而后面的文件名却不是我们要得,怎么解决?一个思路就是将这个结果保存到一个文件中,然后使用
cut等命令对文件进行改造,接着再去统计,这个方法个人感觉比较麻烦。那么第二个思路就是用
awk,直接对我们的结果进行分割。按照思路二,那我们就对此进行编码了
使用
find,对于find,参数较多,考虑到有时候源代码中目录层次不一,我们需要加上参数
maxdepth, 再考虑到所统计的语言项目不一样,我们同样要指定
name这个参数,而且采用一个简单的正则表达式。所以基本的find语句如下:
find $1 -type f -maxdepth $2 -name "*.$3"
这边的
$1是路径名
$2指定的最大深度
$3文件的后缀名或是一些正则的表达式,$3的这个设计我原先的打算是做一个test,根据用户输入,然后最后自己生成正则,感觉这样有点多此一举了。一个项目中使用的文件后缀一般不会很多,统计的是核心代码,所以这一块就可以简便一点了。
统计行数的核心就是如下的这个:
w =(wc -l $file | awk "{print $1}")
这边的file就是之前find的返回值,我们将上面的这个代码放在一个循环中。这边是awk的最简单使用了,将一个记录的第一个字段打印出来。但是不要混淆了这边的
$1和shell脚本的中的
$1是不一样的,这在awk的命令中,所以不要担心会出错。
加一些修饰
我们为了让输出变得好看一点,对echo的输出加一些修饰,主要是颜色的修饰:
echo -e "$s: \e[1;32m $t \e[0m" echo -e "\e[1,31m total: \e[1;32m $w \e[0m"
好了,至此一个基本上能够满足要求的代码统计的脚本就完成了,一个完整的版本可以到我的gist看。
效果截图
C版本
之所以想到使用c来统计,是因为这是在linux平台上,可以使用系统编程方面的一些东西来解决这个问题。因为这个不在标准c中提供对目录的操作 对于windows下面,我没有去研究,所以不好多加叙述。我们来看看如何实现C版本的统计程序?首先等解决的就是一个文件遍历的问题,这个解决不了接下去的工作就不用考虑。好在在linux中提供了一个 dirent.h的头文件,相关的函数都在这里面。我们可以用的是
opendir
readdir
telldir
seekdir
closedir着几个函数,这写函数基本就是差不多了,还缺的一个就是更改目录的函数
chdir这个函数的实现在
unistd.h中,所以这些基本上就齐了。
readdir返回的是一个结构体,结构体中有一个参数d_name,这是保存的文件的名字,所以有了这个,我们就可以对其进行属性的判断了。因为我们要判断这是文件还是目录。
如何判断?没有shell中
if [ -d filename ]这样快捷的判断,但是我们要想到的一点就是,这是在liunx中,一切皆文件,对于文件的属性的判断,我们可以利用
lstat()
这个函数是在
sys/stat.h中,我们使用
lstat(filename,&statbuf)然后就可以用宏还进行判断了
S_ISDIR(statbuf.st_mode). 这样就解决了文件类型的判断。
接着我们来考虑如何来遍历一个文件夹呢?首先的着肯定是在一个循环下。因为一个目录下有时不止一个文件,但是对于不同的目录的时候呢?例如一个目录下的一个子目录,如何去实现遍历?我们考虑到的是使用递归,递归调用我们写的那个函数。因为每次读取的目录只有一个。而且当
readdir读到文件尾的时候回返回一个NULL。 也许你会问这个递归是如何实现的。我们在循环结束后,调用了
chidr("..")回到上层,这样就继续遍历。这就是递归终止的条件。
是时候统计代码了,我们剔除了目录的文件,剩下的就是真正的文件了。对于统计使用fgets来实现遍历一个文件,然后加个循环就解决问题。这边一个不好的就是没有办法去判断文件的类型,统计是对目录下所以的文件进行的统计,这一点不如shell的灵活。
下面是源代码,基本的思路就是这样,还要注意的一个细节是有两个特殊的目录就是
.和
..我们要忽略掉,不然会产生一个死循环。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <dirent.h> /*some functions option on dir*/ #include <sys/stat.h> #define MAXLINE 200 int linecount=0; /*for save the countline*/ int getLine(char *fname) { FILE *fp; char line[MAXLINE]; int total = 0; fp = fopen(fname,"r"); while(fgets(line,200,fp) != NULL) total++; return total; } /*Recurse a the target dirent*/ void Recur_dir(const char *dir, int depth) { DIR *dp; /*dir pointer*/ struct dirent *entry; /*structure to save dir info*/ struct stat statbuf; /*use to charge which is dir and which is file*/ /*get the decriptor*/ if((dp = opendir(dir)) == NULL) { printf("cannot open directory:%s\n",dir); fprintf(stderr,"opendir error:%s\n",strerror(errno)); exit(1); } chdir(dir); /*enter into target dir*/ while((entry = readdir(dp)) != NULL) { lstat(entry->d_name,&statbuf);/*get the entry status*/ if(S_ISDIR(statbuf.st_mode)) { /*is a dirctory and ignore the .. and .*/ if(strcmp(".",entry->d_name)== 0 || strcmp("..",entry->d_name) == 0) continue; //printf("%*s%s\n",depth,"",entry->d_name); Recur_dir(entry->d_name,depth+4); /*continue to open */ } else /*if not a dirctroy and we count the line*/ { linecount += getLine(entry->d_name); /*count everyfile line*/ } } chdir(".."); closedir(dp); } int main(int argc, const char *argv[]) { char *topdir = "." if(argc > 2) { printf("Usage:%s dir\n",argv[0]); exit(1); } if(argc == 2) { topdir = argv[1]; } Recur_dir(topdir,0); printf("Total:%d\n",linecount); return 0; }
如果不提供参数,就遍历当前目录,提供了就统计给出的目录。
效果截图
相关文章推荐
- 一些页面自动跳转的实现 转自<a href="http://www.blogjava.net/Jcat/archive/2006/11/22/82831.html" target="_blank">http://www.blogjava.net/Jcat/archive/2006/11/22/82831.html</a>
- <<字符串高级截取和统计>>一文的C#正则实现
- 艾伟_转载:数组排序方法的性能比较(中):Array.Sort<T> 实现分析
- 一起谈.NET技术,数组排序方法的性能比较(中):Array.Sort<T> 实现分析
- Javascript一些方法和属性总结 <转自他人>
- 解决 ”不允许在查询中显式构造实体类型“问题及使用其他方法实现返回 List<Model对象>或者IQueryable<Model对象>对象
- 交换两个数的值Swap的一些方法及其源代码实现
- <<字符串高级截取和统计>>一文的C#正则实现
- asp.net 实现省市级联-----<简单方法1>
- asp.net 实现省市级联-----<简单方法2>----前台实现
- Struts2中表单数据怎样实例化 <input name=user.name>struts实现拿值方法
- List<T>泛型数组API自带的Sort() 排序方法根据自定义排序实现
- 关于JSP中单击任意标签弹出文件选择框(<input type="file"/>)的实现方法
- <UI>实现背景拉伸的方法(聊天气泡)
- 数组排序方法的性能比较(2):Array.Sort<T>实现分析
- 从源代码编译安装Qt开发工具如(KDevelop)时遇到:Qt (>= Qt 3.3 and < 4.0)解决方法
- 使用Enumerable.OfType<T>扩展方法实现非泛型集合的Linq查询
- html <select> <option> 实现根据选择不同的option,调用不同的方法功能
- 统计报表中嵌入<a>标签,点击实现弹出清单功能
- 在IE 6中<a>标签的一些bug和解决方法