主要是老师要求每天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;
}