天天看点

20150123 【 Linux-C 文件目录操作 】 统计代码行数

主要是老师要求每天200行,

于是就写了一个用来 统计文件内代码行数的程序。

程序执行时,加上文件夹路径和文件后缀(其实是文件名的片段),

就能统计出 此文件夹下的该类文件的行数以及有效行数(一些用于格式调整【空格,制表,回车】的不算)。

----------------------------

本来还想把注释也干掉的,

可是注释两种情况(单行//和多行)

其中单行好处理;

但是多行要跨行,比较麻烦

所以我就一视同仁,没有处理注释了。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>


/**
* 默认文件目录路径	NOW_PATH
* 最大文件目录长度	DIR_LEN
* 最大文件名长度	FILE_LEN
* 最大文件数		FILE_NUM
* 默认文件后缀		SUFFIX_NAME
*/
#define NOW_PATH	"."
#define DIR_LEN		1024
#define FILE_LEN	512
#define FILE_NUM	520
#define SUFFIX_NAME	".c"


//错误描述符
const enum ERROR_STATE{OpenProgarmError=0x77889900, OpenDirError, OpenFileError};


//空白符号集合 blank_char	空白符号数目 blank_len
const char blank_char[] = {'\n', '\t', ' ', '\\', '\0'};
const int blank_len = sizeof(blank_char);

//默认文件目录路径 dirPath	默认文件后缀 fileSuffix
char dirPath[DIR_LEN]  = NOW_PATH;
char fileSuffix[FILE_LEN] = SUFFIX_NAME;

//字符串容器 tempStr	文件数 fLen
char tempStr[(DIR_LEN+FILE_LEN)<<2];
int fLen = 0;


/**
* 文件属性结构体 fileAttr
* 	文件描述号 fd
* 	文件行数 len
* 	文件有效行数 noLen
* 	文件名称 name
*/
typedef struct _fileAttr
{
	int	fd;
	int	len;
	int	noLen;
	char	name[FILE_LEN];
}fileAttr;

//文件属性组
fileAttr fAttr[FILE_NUM];


/**	判断字符串是否都是由空白字符组成的
* 输入参数:	指向目标字符串的字符指针*ss
* 函数功能:	判断该字符串是否都是由空白字符(blank_char集合)组成
* 输出参数:	1:都由空白字符组成	0:不是非空字符串
*/
int is_blank_line(char *ss)
{
	int i=0, j=0, ssLen=0;

//遍历 目标字符串 (一共 ssLen 个字符)
	for(i=0, ssLen=strlen(ss); i<ssLen; i++)
	{
//简单粗暴的暴力查找(其实可以使用更快的数组定位,但是闲麻烦,就没写了)
		for(j=0; j<blank_len && blank_char[j]!=ss[i] ; j++);

/*
* 正常情况下(都不是空白字符),
* 	遍历完 blank_char 集合才退出
* 	(此时j=blank_len,说明是非空字符串)
*/
	if( j==blank_len )
		return 0;
	}
	return 1;
}


/**	计算该文件的行数(所有行数,有效行数)
* 输入参数:文件属性结构体指针 fa
* 函数功能:获取该文件所有行,算出有效行数
* 输出参数:无
*/
void counter_line(fileAttr *fa)
{
	int i=0;
	
//把文件描述号 fAttr.fd 转换成 文件描述指针
	FILE * fp = fdopen(fa->fd, "r");
	while( !feof(fp) ) 
	{
/*
* 读入一行(假设一行不超过 (DIR_LEN+FILE_LEN)<<2 个字符 )
* 统计行数(有效行数)
*/
		fgets(tempStr, (DIR_LEN+FILE_LEN)<<2, fp);
		fa->len++;
		fa->noLen += !is_blank_line(tempStr);
	}
}


/**	输出该文件目录下所有文件的统计情况
* 输入参数:无
* 函数功能:把文件目录内所有文件信息输出
* 输出参数:无
*/
void show_code_counter(void)
{
	int i=0;

//统计行数,非空行数
	int sumLine=0, sumNoLine=0;

//输出标题行(当前路径;文件后缀;序号,代码行数,有效行数,文件名称)
	printf("\t当前路径:\"%s\"\n", dirPath);
	printf("\t文件后缀:\"%s\"\n", fileSuffix);
	printf("---------------------------------------\n");
	printf("%4s %8s %8s %s\n", "序号", "代码行数", "有效行数", "文件名称");

//计算该目录下所有文件
	for(i=0; i<fLen; i++)
	{

//该文件属性( fAttr.len , fAttr.noLen )初始化
		fAttr[i].len = fAttr[i].noLen = 0;
	
//计算该文件行数 fAttr.len , 有效行数 fAttr.noLen
		counter_line(&fAttr[i]);
	
//输出文件描述号,文件行数,有效行数,文件名称
		printf("%4d %8d %8d %s\n", fAttr[i].fd, fAttr[i].len, fAttr[i].noLen, fAttr[i].name);

//统计文件 总行数 sumLine , 有效行数 sumNoLine
		sumLine += fAttr[i].len;
		sumNoLine += fAttr[i].noLen;
	}

//输出统计信息 总行数 sumLine , 有效行数 sumNoLine
	printf("---------------------------------------\n");
	printf("一共有 %d 个文件,合计 %d 行,有效 %d 行......\n\n\n", fLen, sumLine, sumNoLine);
}

int main(int argc, char **argv)
{
	int i=0;

//程序是否正确打开,失败返回 OpenProgarmError	
	if( argc <= 0 )
	{
		fprintf(stderr, "「程序运行出错」...\n\n");
		exit( OpenProgarmError );
	}
	
//如果追加路径,则更新文件目录路径 dirPath

	if( argc >= 2 )
	{
		strncpy(dirPath, argv[1], DIR_LEN);
	}

//如果追加文件后缀,则更新文件后缀 fileSuffix
	if( argc >=3 )
	{
		strncpy(fileSuffix, argv[2], FILE_LEN);
	}
	

//打开文件目录目录 fdDir,失败返回 OpenDirError
	DIR * fdDir = opendir(dirPath);
	if( fdDir == NULL )
	{
		fprintf(stderr, "「打开目录出错」 %s\n\n", dirPath);
		exit( OpenDirError );
	}

/**
* 目录内容结构体 f_dirent,
* 	获取目录内所有文件;
* 文件信息有:
* 	文件描述号 fAttr.fd
* 	文件名 fAttr.name
*/
	struct dirent * f_dirent = NULL;
	while( ( f_dirent=readdir(fdDir) ) != NULL )
	{
//查找目标文件(具有 fileSuffix 后缀的文件)
		if( strstr(f_dirent->d_name, fileSuffix) )
		{

//获取文件的绝对或相对路径dirPath/fAttr.name(文件目录路径/文件名)
			snprintf(tempStr, (DIR_LEN+FILE_LEN)<<2, "%s/%s", dirPath, f_dirent->d_name);
			
//获取文件描述号 fd 和文件名 name

			fAttr[fLen].fd = open(tempStr, O_RDONLY);
			strncpy(fAttr[fLen].name, f_dirent->d_name, FILE_LEN);

//文件是否打开,失败返回 OpenFileError
			if( fAttr[fLen++].fd < 0 )
			{
				fprintf(stderr, "「打开文件失败」 %s\n\n", tempStr);
				exit( OpenFileError );
			}
		}
	}

/*
* 输出文件目录路径 dirPath 和文件后缀 fileSuffix
* 以及该路径下所有目标文件的:
* 文件描述号fd ,文件行数len ,有效行数noLen ,文件名称name
* 总计 行数sumLine 和 有效行数sumNoLine
*/	
	show_code_counter();

/*
* 关闭文件目录 fdDir
* 关闭所有文件 fAttr.fd
*/
	closedir( fdDir );
	for(i=0; i<fLen; i++)
	{
		close( fAttr[i].fd );
	}
	
	return 0;
}
           

继续阅读