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