文件行数统计程序

简单实现

逻辑

  1. 打开文件
  2. 读取一行不为空,行数 + 1
  3. 重复 2 ,直到读完
  4. 输出结果

代码实现

#include <stdio.h>

int main()
{
    FILE *file;
    char line[1024]; // 假设每行不超过1024个字符

    // 打开文件
    file = fopen("example.txt", "r");
    if (file == NULL) {
        printf("无法打开文件\n");
        return 1;
    }

    int lineCount = 0;

    // 逐行读取文件
    while (fgets(line, sizeof(line), file) != NULL)
    {
        // 每读取一行,行数加一
        lineCount++;
    }

    // 关闭文件
    fclose(file);

    // 输出结果
    printf("文件中的行数: %d\n", lineCount);
    return 0;
}

进阶:分别统计文件中代码、注释、空行行数

逻辑

  1. 实现不同文件的统计
  2. 在简单版本基础上,增加对于每行具体内容的判断

实现

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

int main(int argc, char *argv[])
{ 
    // argc : 参数个数,argv : 参数数组
    if (argc != 2) {
        printf("缺少参数\n使用方式: %s <filename>\n", argv[0]); // argv[0] : 程序名,argv[1] : 文件名
        return 0;
    }

     FILE *file;
    char buf[1024];
    int total_line = 0;
    int code_line = 0;
    int comment_line = 0;
    int blank_line = 0;
    int in_multiline_comment = 0;

     // 打开文件
    file = fopen(argv[1], "r");
    if (file == NULL) {
        printf("无法打开文件\n");
        return 1;
    }

    // 逐行读取文件
    while (fgets(buf, sizeof(buf), file) != NULL)
    {
        total_line++; // 总行数

        // 去掉行首和行尾的空白字符
        char *trimmed_line = buf;
        while (*trimmed_line == ' ' || *trimmed_line == '\t')
        {
            trimmed_line++;
        }

        // 检查是否为空行
        if (strlen(trimmed_line) == 0 || trimmed_line[0] == '\n')
        {
            blank_line++;
        } 
        // 检查多行注释
        else if (in_multiline_comment)
        {
            comment_line++;
            if (strstr(trimmed_line, "*/") != NULL)
            {
                in_multiline_comment = 0; // 结束多行注释
            }
        } 
        // 检查单行注释
        else if (strncmp(trimmed_line, "//", 2) == 0)
        {
            comment_line++;
        } 
        // 检查多行注释的开始
        else if (strstr(trimmed_line, "/*") != NULL)
        {
            comment_line++;
            in_multiline_comment = 1; // 进入多行注释状态
            if (strstr(trimmed_line, "*/") != NULL)
            {
                in_multiline_comment = 0; // 结束多行注释
            }
        } 
        // 其他情况视为代码行
        else
        {
            code_line++;
        }
    }

    // 关闭文件
    fclose(file);

    // 计算总行数
    int totalLines = total_line;

    // 输出结果
    printf("代码行数: %d (%.2f%%)\n", code_line, (double)code_line / totalLines * 100);
    printf("注释行数: %d (%.2f%%)\n", comment_line, (double)comment_line / totalLines * 100);
    printf("空行数: %d (%.2f%%)\n", blank_line, (double)blank_line / totalLines * 100);

    return 0;
}

运行结果

zpy@Ubuntu-22:~/Course/line_count$ ./l lines+.c
代码行数: 147 (74.24%)
注释行数: 23 (11.62%)
空行数: 28 (14.14%)

进阶:统计一个文件夹内所有 C 源文件和头文件

逻辑

  1. 打开目标文件夹
  2. 遍历每个文件,查看是否C文件
  3. 执行统计

实现

#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <dirent.h> // 用于目录操作

#define MAX_PATH 1024
#define BUFFER_SIZE 1024

int is_c_or_h_file(const char *filename) {
    // 判断文件是否为 .c 或 .h 文件
    const char *extension = strrchr(filename, '.');
    if (extension == NULL) return false;
    return !strcmp(extension, ".c") || !strcmp(extension, ".h");
}

int main(int argc, char *argv[])
{
    // argc : 参数个数,argv : 参数数组
    if (argc != 2)
    {
        printf("缺少参数\n使用方式: %s <directory>\n", argv[0]); // argv[0] : 程序名,argv[1] : 目录名
        return 0;
    }

    DIR *dir;
    struct dirent *entry;
    char path[MAX_PATH];

    // 打开目录
    dir = opendir(argv[1]);
    if (dir == NULL)
    {
        perror("无法打开目录");
        return 1;
    }

    int total_code_lines = 0;
    int total_comment_lines = 0;
    int total_blank_lines = 0;
    int total_files_processed = 0;

    // 遍历目录中的文件
    while ((entry = readdir(dir)) != NULL)
    {
        // 忽略当前目录和父目录
        if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) continue;

        snprintf(path, sizeof(path), "%s/%s", argv[1], entry->d_name);

        // 只处理 .c 和 .h 文件
        if (!is_c_or_h_file(entry->d_name)) continue;

        FILE *file;
        char buf[BUFFER_SIZE];
        int total_line = 0;
        int code_line = 0;
        int comment_line = 0;
        int blank_line = 0;
        int in_multiline_comment = 0;

        // 打开文件
        file = fopen(path, "r");
        if (file == NULL)
        {
            printf("无法打开文件 %s\n", path);
            continue;
        }

        // 逐行读取文件
        while (fgets(buf, BUFFER_SIZE, file) != NULL)
        {
            total_line++; // 总行数

            // 去掉行首和行尾的空白字符
            char *trimmed_line = buf;
            while (*trimmed_line == ' ' || *trimmed_line == '\t')
            {
                trimmed_line++;
            }

            // 检查是否为空行
            if (strlen(trimmed_line) == 0 || trimmed_line[0] == '\n')
            {
                blank_line++;
            } 
            // 检查多行注释
            else if (in_multiline_comment)
            {
                comment_line++;
                if (strstr(trimmed_line, "*/") != NULL)
                {
                    in_multiline_comment = 0; // 结束多行注释
                }
            } 
            // 检查单行注释
            else if (strncmp(trimmed_line, "//", 2) == 0)
            {
                comment_line++;
            } 
            // 检查多行注释的开始
            else if (strstr(trimmed_line, "/*") != NULL)
            {
                comment_line++;
                in_multiline_comment = 1; // 进入多行注释状态
                if (strstr(trimmed_line, "*/") != NULL)
                {
                    in_multiline_comment = 0; // 结束多行注释
                }
            } 
            // 其他情况视为代码行
            else
            {
                code_line++;
            }
        }

        // 关闭文件
        fclose(file);

        // 更新总计
        total_code_lines += code_line;
        total_comment_lines += comment_line;
        total_blank_lines += blank_line;
        total_files_processed++;

        // 输出单个文件的结果
        printf("%s: 代码行数: %d, 注释行数: %d, 空行数: %d\n", path, code_line, comment_line, blank_line);
    }

    // 关闭目录
    closedir(dir);

    // 计算总行数
    int totalLines = total_code_lines + total_comment_lines + total_blank_lines;

    // 输出结果
    printf("\n总计处理文件数: %d\n", total_files_processed);
    printf("总计代码行数: %d (%.2f%%)\n", total_code_lines, (double)total_code_lines / totalLines * 100);
    printf("总计注释行数: %d (%.2f%%)\n", total_comment_lines, (double)total_comment_lines / totalLines * 100);
    printf("总计空行数: %d (%.2f%%)\n", total_blank_lines, (double)total_blank_lines / totalLines * 100);

    return 0;
}

运行结果

../line_count//l.c: 代码行数: 85, 注释行数: 24, 空行数: 21
../line_count//lines+.c: 代码行数: 147, 注释行数: 23, 空行数: 28

总计处理文件数: 2
总计代码行数: 232 (70.73%)
总计注释行数: 47 (14.33%)
总计空行数: 49 (14.94%)

进阶:统计一个文件夹内所有文件和文件夹

逻辑

  1. 遍历文件夹内的 C 文件
  2. 遇到文件夹时,递归遍历其中的内容

实现

#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <dirent.h> // 用于目录操作

#define MAX_PATH 1024
#define BUFFER_SIZE 1024

// 定义文件统计信息结构体
typedef struct FileStats
{
    int code_lines;
    int comment_lines;
    int blank_lines;
} FileStats;

// 判断文件是否为 .c 或 .h 文件
bool is_c_or_h_file(const char *filename)
{
    const char *extension = strrchr(filename, '.');
    if (extension == NULL) return false;
    return !strcmp(extension, ".c") || !strcmp(extension, ".h");
}

// 处理单个文件
FileStats process_file(const char *file_path)
{
    FILE *file;
    char buf[BUFFER_SIZE];
    int total_line = 0;
    int code_line = 0;
    int comment_line = 0;
    int blank_line = 0;
    int in_multiline_comment = 0;

    // 打开文件
    file = fopen(file_path, "r");
    if (file == NULL) {
        printf("无法打开文件 %s\n", file_path);
        return (FileStats){0, 0, 0};
    }

    // 逐行读取文件
    while (fgets(buf, BUFFER_SIZE, file) != NULL)
    {
        total_line++; // 总行数

        // 去掉行首和行尾的空白字符
        char *trimmed_line = buf;
        while (*trimmed_line == ' ' || *trimmed_line == '\t')
        {
            trimmed_line++;
        }

        // 检查是否为空行
        if (strlen(trimmed_line) == 0 || trimmed_line[0] == '\n')
        {
            blank_line++;
        } 
        // 检查多行注释
        else if (in_multiline_comment) {
            comment_line++;
            if (strstr(trimmed_line, "*/") != NULL)
            {
                in_multiline_comment = 0; // 结束多行注释
            }
        } 
        // 检查单行注释
        else if (strncmp(trimmed_line, "//", 2) == 0)
        {
            comment_line++;
        } 
        // 检查多行注释的开始
        else if (strstr(trimmed_line, "/*") != NULL)
        {
            comment_line++;
            in_multiline_comment = 1; // 进入多行注释状态
            if (strstr(trimmed_line, "*/") != NULL)
            {
                in_multiline_comment = 0; // 结束多行注释
            }
        } 
        // 其他情况视为代码行
        else {
            code_line++;
        }
    }

    // 关闭文件
    fclose(file);

    // 返回文件统计信息
    return (FileStats){code_line, comment_line, blank_line};
}

// 递归处理文件夹
void process_directory(const char *directory_path, int *total_code_lines, int *total_comment_lines, int *total_blank_lines, int *total_files_processed) {
    DIR *dir;
    struct dirent *entry;
    char path[MAX_PATH];
    FileStats stats;

    // 打开目录
    dir = opendir(directory_path);
    if (dir == NULL)
    {
        perror("无法打开目录");
        return;
    }

    // 遍历目录中的文件
    while ((entry = readdir(dir)) != NULL)
    {
        // 忽略当前目录和父目录
        if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) continue;

        snprintf(path, sizeof(path), "%s/%s", directory_path, entry->d_name);

        // 如果是文件夹,则递归处理
        if (entry->d_type == DT_DIR)
        {
            process_directory(path, total_code_lines, total_comment_lines, total_blank_lines, total_files_processed);
            continue;
        }

        // 只处理 .c 和 .h 文件
        if (!is_c_or_h_file(entry->d_name)) continue;

        stats = process_file(path);

        // 更新总计
        *total_code_lines += stats.code_lines;
        *total_comment_lines += stats.comment_lines;
        *total_blank_lines += stats.blank_lines;
        (*total_files_processed)++;

        // 输出单个文件的结果
        // printf("%s: 代码行数: %d, 注释行数: %d, 空行数: %d\n", path, stats.code_lines, stats.comment_lines, stats.blank_lines);
    }

    // 关闭目录
    closedir(dir);
}

int main(int argc, char *argv[])
{
    // argc : 参数个数,argv : 参数数组
    if (argc != 2) {
        printf("缺少参数\n使用方式: %s <directory>\n", argv[0]); // argv[0] : 程序名,argv[1] : 目录名
        return 0;
    }

    int total_code_lines = 0;
    int total_comment_lines = 0;
    int total_blank_lines = 0;
    int total_files_processed = 0;

    // 调用递归函数处理文件夹
    process_directory(argv[1], &total_code_lines, &total_comment_lines, &total_blank_lines, &total_files_processed);

    // 计算总行数
    int totalLines = total_code_lines + total_comment_lines + total_blank_lines;

    // 输出结果
    printf("\n总计处理文件数: %d\n", total_files_processed);
    printf("总行数: %d\n", totalLines);
    printf("总计代码行数: %d (%.2f%%)\n", total_code_lines, (double)total_code_lines / totalLines * 100);
    printf("总计注释行数: %d (%.2f%%)\n", total_comment_lines, (double)total_comment_lines / totalLines * 100);
    printf("总计空行数: %d (%.2f%%)\n", total_blank_lines, (double)total_blank_lines / totalLines * 100);

    return 0;
}

运行结果

zpy@Ubuntu-22:~/Course/line_count$ ./l redis-stable/

总计处理文件数: 704
总行数: 294153
总计代码行数: 200251 (68.08%)
总计注释行数: 59294 (20.16%)
总计空行数: 34608 (11.77%)

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值