寫一個程序,統計本身C語言共寫了多少行代碼。ver2.00

概要

完成一個程序,做用是統計一個文件夾下面全部文件的代碼行數。輸入是一個文件夾的絕對路徑,輸出是代碼行數。因此此程序的新特色有兩個:html

  1. 統計某一文件夾下的全部文件;
  2. 能夠任意指定本機硬盤上任何位置的某一個文件夾。

前言

上一篇隨筆中熟悉了文件的基本操做。但仍然有改進的餘地:統計特定文件時,仍是須要手動輸入文件名。若是文件數量不少怎麼辦?可不能夠直接統計某個文件夾下面的全部文件的代碼行數?今天解決的就是這個問題。linux

思考

咱們已經解決了一個問題:寫一個帶有文件操做的C語言程序,輸入文件名,輸出此文件下的換行數。git

考慮了一下現有的成果以及新增的目標,有須要更改的地方應該是輸入,由文件名換成一個文件夾,而後經過程序掃描一遍這個文件夾下面全部的文件。而後讀取全部的文件名,存放到數組裏。再把字符串由fopen一個個調用,統計行數。細節差很少是這樣,但總歸要先掃描文件夾吧!github

怎麼掃描文件夾下面的文件?

搜索引擎搜索:C語言怎麼掃描文件目錄?編程

有找到幾個連接,比較有用,能夠參考:windows

比較惋惜的是,上述網站提供的參考方法有使用函數opendir,查找了一下,發現這是一個在Linux系統下的函數。本人沒有用過Linux。想了想,並無直接開始搜索「安裝Linux教程」,我心想:總有不用這個函數的方法吧!因而依舊在搜索引擎上不斷地尋找。網站

找了接近一小時也無果,我打算換個問法。因而我在搜索引擎打入了:統計一個文件夾下文件

馬上映入我眼簾的就有一個黑科技,我驚呆了。

我馬上在桌面按照步驟進行實驗。不得不說,看到結果,我很是滿意。這不就我要的文件夾下面的全部文件名的字符串組合嘛!

馬上經過編程實現這一功能,效果拔羣

#include<stdio.h>

int main()
{
    FILE *fp;
    
    fp = fopen("TEXT.bat","w");
    fputs("DIR *.* /B> LIST.TXT",fp);
    fclose(fp);
    
    return 0; 
}

這裏面有一行神祕的操做碼,

DIR *.* /B> LIST.TXT

問題來了,這一行代碼究竟是什麼呢?仍是搜索引擎幫助你:)

大概知道了:

  • dir 顯示目錄中的文件和子目錄列表;

  • /B 使用空格式(沒有標題信息或摘要);

  • * . * (兩個星號中間一個句點)就是說顯示全部文件,文件名和擴展名沒有限制。舉例說明:若是是*.txt,則是顯示全部擴展名爲txt的文件;

  • 最後面是字符串,很容易就知道是重定向輸出的文件名。

好了。那麼進行下一步的操做。咱們考慮到一個文件夾只統計C語言代碼的行數,因此這裏我考慮只對.c後綴的文件進行這種操做。

#include<stdio.h>
int main()
{
    FILE *fp;
    
    fp = fopen("Text.bat","w");
    fputs("DIR *.c /B> list.txt",fp);
    fclose(fp);
    
    fp=fopen("Text.bat","r");
    fclose(fp);
    
    return 0; 
}

這兒遇到了第一個問題,運行可執行文件main.exe以後,文件夾內的文件狀況以下圖:

沒有產生預期想要得到的文本文件list.txt。看來問題出在:

fp = fopen("Text1.bat","r");

這行語句上。由於,已經正常生成.bat文件,而且雙擊運行的話仍是能生成文本文件,說明.bat文件沒有問題,應該是打開文件的方式有問題

馬上搜索:c語言打開bat文件。獲得解決方法:

在程序中使用system() 函數。
假設bat文件的名稱叫a.bat 即:
system("a.bat");

經過搜素來的方法,輕鬆解決這個問題。

#include<stdio.h>
int main()
{
    FILE *fp;
    
    fp = fopen("Text.bat","w");
    fputs("DIR *.c /B> list.txt",fp);
    fclose(fp);
    
    system("Text.bat");
    return 0; 
}

編譯後運行結果:

獲得了咱們想要的list.txt。也就是說.bat文件被正確地執行了。生成LIST的工做已經完成。如今已經有了存儲文件名字符串的文本文件,下面只須要從這些文件中讀取文件名,再調用上一篇隨筆中實現的功能,便可實現此次須要添加的新功能了。

實現的簡單的從list.txt中讀取文件名。打開文件進行行數統計:

#include<stdio.h>
#include<Windows.h>
#include<string.h>

int main()
{ 
    FILE *fp;
    fp = fopen("Text.bat","w");
    fputs("DIR *.c /B>list.txt",fp);
    fclose(fp);
    system("Text.bat"); 
    /*~~~the end of creating file name list~~~*/
    
    /*~~~the beginning of get .c file name from list~~~*/
    static int count = 0; 
    FILE *fp1, *fp2;
    fp1 = fopen("list.txt","r");
    char s[100], singleline[1000];
    while(fgets(s, 100, fp1))//get the name(one line) of a file from the list
    {
    //  int len=strlen(s);
    //  if(s[len-1]=='\n') s[len-1]='\0';   what is this?
        printf("%s: ",s);   
        fp2 = fopen(s,"r");//open the correct file, according to the file name
        while(fgets(singleline, 1000, fp2))
        {
            count++;
        }   
        printf("%d\n", count);
        fclose(fp2);
    }
    printf("\n");
    fclose(fp1);
    
    system("pause");
    return 0;
}

咱們先不要管帶有註釋 what is this? 的那一行代碼。

編譯後執行,此次我在可執行文件.exe的目錄下放了一些.c文件進行測試,看看運行結果如何:

我以爲代碼意思都很明瞭了,然而執行結果仍是失敗的。

仔細觀察結果,發現幾個奇怪的點。

  • .c文件是沒問題的,統計代碼行數的幾行代碼是由上一個版本引進的因此也應該是沒問題的,可是結果倒是0;
  • 輸出中有多餘的空行

找到問題所在了!因爲fgets函數碰到'\n'是會中止輸入的,\n留在了緩衝區,下一次fgets時會致使文件讀取失敗(我的猜測,可能有誤)因此咱們要設法處理掉這個'\n'。

思考一下,數組s是存儲文件名的。舉"C++.txt"爲例,假設形成讀入失敗的緣由是字符串後面跟了一個\n

C + + . t x t \n \0

'\n'的位置是s[strlen(s)-1]爲此咱們經過以下代碼進行debug

int len=strlen(s);
if(s[len-1]=='\n') 
    s[len-1]='\0';

再次編譯運行,完成功能。此時距離成功已經很近了!

如何指定任意的文件夾路徑?絕對路徑!

絕對路徑是什麼?請看下面的代碼:

FILE * fp;
fp = fopen("test.txt", "r");

咱們知道fopen函數的第一個參數是一個字符串,表明文件名,這裏的"test.txt"就不是絕對路徑,而是當前文件夾下(也能夠理解爲.exe可執行程序的文件夾)的文件。若是要使用絕對路徑名,就把絕對路徑輸入進第一個參數便可。怎麼看文件夾or文件的絕對路徑呢?

很簡單,鼠標右鍵,屬性,就能夠看了。例如上圖test的文件夾的絕對路徑是E:\test

這裏有一個注意點,在代碼中操做字符串時,要想表明輸入一個反斜槓,須要輸入兩個反斜槓。你們還記得轉義字符嗎?還有就是注意輸入時要把中文輸入法關掉了。

貼上比較粗略的代碼,附贈註釋,以及執行效果圖一張:

#include<stdio.h>
#include<Windows.h>
#include<string.h>
int main()
{ 
    char filepath[1000], batpath[1010]; //the absolute path of a file folder and a .bat file.
    gets(filepath);//input absolute path of a file folder
    strcpy(batpath, filepath);
    strcat(batpath, "\\Text1.bat");
    FILE *fp;
    fp = fopen(batpath, "w");
    fputs("DIR *.c /B>list.txt", fp);
    fclose(fp);
    system(batpath); 
    /*~~~the end of creating file name list~~~*/
    
    /*~~~the beginning of get .c file name from list~~~*/
    static int count = 0; 
    FILE *fp1, *fp2;
    fp1 = fopen("list.txt", "r");
    char s[100];
    char singleline[1000];
    while(fgets(s, 100, fp1))//get one line from list, each line refers to a .c file name
    {
        int len = strlen(s);
        if(s[len-1] == '\n') s[len-1] = '\0';
        printf("%s: ", s);  
        fp2 = fopen(s, "r");
        
        /*~~~the beginning of counting lines of code~~~*/
        
        while(fgets(singleline, 1000, fp2))//open the correct file, according to the file name
        {
            count++;
        }   
        printf("%d\n", count);
        fclose(fp2);
    }
    printf("\n");
    fclose(fp1);
    
    system("pause");
    return 0;
}

由圖片能夠看出,咱們想要的功能:輸入一個文件夾的路徑,統計文件夾下面的.c文件的代碼行數,已經實現了。

主要的工做實現原理都在上面這段代碼裏,最後要作的工做就是

  • 封裝;
  • 實現可循環輸入;
  • 錯誤信息提示;
  • 考慮改改變量名、增長一點宏定義什麼的,讓代碼更具備可讀性;
  • 還能夠考慮添加的功能,例如能夠分別顯示每一個文件各自的代碼行數,最後顯示一個總行數。

稍後我會把完成版代碼推上個人github。

後記

想了想仍是要感謝下棟哥的啓發式教學,讓我完成了一個小小的東西,雖然沒啥技術含量吧,可是也是本身獨立完成的,成就感仍是有的。

這個問題我想了一早上,到了中午卡在絕對路徑那兒,結果頭暈暈的就去睡午覺了,醒來以後才解決的。233

最後,固然就是有什麼錯誤,或者是有疑惑的地方均可以跟我說哦!

相關文章
相關標籤/搜索