程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> <轉>統計源代碼行數的一些實現方法,源代碼行數

<轉>統計源代碼行數的一些實現方法,源代碼行數

編輯:關於C語言

<轉>統計源代碼行數的一些實現方法,源代碼行數


這個問題的思考其實對於某一種語言而言,基本都能實現,只是簡單和復雜而已。而此次我討論就是只是在linux下面使用了shell和c對源代碼進行行 數的討論。本打算是實現一個python版本的,由於python這塊還不是太熟,所以就等以後熟了把這塊補上。

shell版

shell的強大快捷之處就在此體現出來了。我們使用find命令就直接能將目標的文件進行檢索,然後我們就直接對檢索出來的對象進行統計。統計 我們知道使用wc這個命令,但是我們觀察一下wc的輸出:

206 ./2014-03-09-jekyll-blog.md

前面是我們想要的內容,而後面的文件名卻不是我們要得,怎麼解決?一個思路就是將這個結果保存到一個文件中,然後使用cut等命令對文件進行改造,接著再去統計,這個方法個人感覺比較麻煩。那麼第二個思路就是用awk,直接對我們的結果進行分割。按照思路二,那我們就對此進行編碼了

這邊的$1是路徑名 $2 指定的最大深度 $3 文件的後綴名或是一些正則的表達式,$3的這個設計我原先的打算是做一個test,根據用戶輸入,然後最後自己生成正則,感覺這樣有點多此一舉了。一個項目中使用的文件後綴一般不會很多,統計的是核心代碼,所以這一塊就可以簡便一點了。

這邊的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看。

效果截圖

count_sh

C版本

之所以想到使用c來統計,是因為這是在linux平台上,可以使用系統編程方面的一些東西來解決這個問題。因為這個不在標准c中提供對目錄的操作 對於windows下面,我沒有去研究,所以不好多加敘述。

我們來看看如何實現C版本的統計程序?首先等解決的就是一個文件遍歷的問題,這個解決不了接下去的工作就不用考慮。好在在linux中提供了一個 dirent.h的頭文件,相關的函數都在這裡面。我們可以用的是opendir readdirtelldir 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;
    }

如果不提供參數,就遍歷當前目錄,提供了就統計給出的目錄。

效果截圖

count_c

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved