You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让我的C语言程序按文件大小或最后修改时间排序?

如何用C语言实现按文件大小或最后修改时间排序文件?

我来帮你搞定这个需求!要实现按文件大小或者最后修改时间排序文件,核心思路就是先把目录里所有文件的关键元数据收集起来,再用C标准库的qsort()配合自定义的比较规则来排序,最后输出结果。我结合你给出的代码片段,补全并修改成支持排序的完整版本:


完整实现代码

#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<dirent.h>
#include<stdlib.h>
#include<string.h>
#include<pwd.h>
#include<grp.h>
#include<time.h>

#define BUFFERSIZE 4096
#define COPYMODE 0644

// 新增:存储文件信息的结构体,方便排序时统一管理
typedef struct FileInfo {
    char filename[256];
    off_t size;          // 文件大小
    time_t mtime;        // 最后修改时间
    struct stat stat_buf; // 完整的stat信息,用于显示权限等详情
} FileInfo;

void oops(char *, char *);
void do_ls(char[], int);
void show_file_info(char *, struct stat *);
void mode_to_str(mode_t, char[]);
int compare_by_size(const void *, const void *);
int compare_by_mtime(const void *, const void *);

// 错误处理函数
void oops(char *s1, char *s2) {
    fprintf(stderr, "%s: %s\n", s1, s2);
    perror("");
    exit(1);
}

// 按文件大小升序排序(降序则反转返回值)
int compare_by_size(const void *a, const void *b) {
    const FileInfo *fileA = (const FileInfo *)a;
    const FileInfo *fileB = (const FileInfo *)b;
    return (fileA->size > fileB->size) - (fileA->size < fileB->size);
}

// 按最后修改时间升序排序(最新的在后面,降序则反转返回值)
int compare_by_mtime(const void *a, const void *b) {
    const FileInfo *fileA = (const FileInfo *)a;
    const FileInfo *fileB = (const FileInfo *)b;
    return (fileA->mtime > fileB->mtime) - (fileA->mtime < fileB->mtime);
}

// 将stat的mode位转换为可读的权限字符串(如-rwxr-xr-x)
void mode_to_str(mode_t mode, char str[]) {
    strcpy(str, "----------"); // 默认无权限模板

    // 处理文件类型
    if (S_ISDIR(mode)) str[0] = 'd';
    if (S_ISCHR(mode)) str[0] = 'c';
    if (S_ISBLK(mode)) str[0] = 'b';
    if (S_ISFIFO(mode)) str[0] = 'p';
    if (S_ISLNK(mode)) str[0] = 'l';
    if (S_ISSOCK(mode)) str[0] = 's';

    // 处理所有者权限
    if (mode & S_IRUSR) str[1] = 'r';
    if (mode & S_IWUSR) str[2] = 'w';
    if (mode & S_IXUSR) str[3] = 'x';

    // 处理组权限
    if (mode & S_IRGRP) str[4] = 'r';
    if (mode & S_IWGRP) str[5] = 'w';
    if (mode & S_IXGRP) str[6] = 'x';

    // 处理其他用户权限
    if (mode & S_IROTH) str[7] = 'r';
    if (mode & S_IWOTH) str[8] = 'w';
    if (mode & S_IXOTH) str[9] = 'x';
}

// 显示单个文件的详细信息
void show_file_info(char *filename, struct stat *info_p) {
    char mode_str[11];
    mode_to_str(info_p->st_mode, mode_str);

    printf("%s ", mode_str);
    printf("%3ld ", (long)info_p->st_nlink);
    printf("%s %s ", getpwuid(info_p->st_uid)->pw_name, getgrgid(info_p->st_gid)->gr_name);
    printf("%6lld ", (long long)info_p->st_size);
    printf("%.12s ", ctime(&info_p->st_mtime) + 4); // 截取时间部分(跳过星期)
    printf("%s\n", filename);
}

// 核心逻辑:遍历目录、收集文件信息、排序后输出
void do_ls(char dirname[], int sort_type) {
    DIR *dir_ptr;
    struct dirent *direntp;
    FileInfo *file_list = NULL;
    int count = 0;
    int capacity = 10; // 初始数组容量,不够自动扩容

    // 打开目标目录
    if ((dir_ptr = opendir(dirname)) == NULL) {
        oops("Cannot open", dirname);
        return;
    }

    // 初始化文件信息数组
    file_list = malloc(capacity * sizeof(FileInfo));
    if (file_list == NULL) {
        perror("malloc failed");
        closedir(dir_ptr);
        return;
    }

    // 遍历目录,收集每个文件的信息
    while ((direntp = readdir(dir_ptr)) != NULL) {
        // 跳过当前目录(.)和上级目录(..)
        if (strcmp(direntp->d_name, ".") == 0 || strcmp(direntp->d_name, "..") == 0) {
            continue;
        }

        // 拼接文件完整路径
        char full_path[512];
        snprintf(full_path, sizeof(full_path), "%s/%s", dirname, direntp->d_name);

        // 获取文件的stat元数据
        if (stat(full_path, &file_list[count].stat_buf) == -1) {
            oops("Cannot stat", full_path);
            continue;
        }

        // 填充文件信息结构体
        strncpy(file_list[count].filename, direntp->d_name, sizeof(file_list[count].filename)-1);
        file_list[count].filename[sizeof(file_list[count].filename)-1] = '\0';
        file_list[count].size = file_list[count].stat_buf.st_size;
        file_list[count].mtime = file_list[count].stat_buf.st_mtime;

        count++;

        // 数组容量不足时自动扩容
        if (count >= capacity) {
            capacity *= 2;
            FileInfo *temp = realloc(file_list, capacity * sizeof(FileInfo));
            if (temp == NULL) {
                perror("realloc failed");
                free(file_list);
                closedir(dir_ptr);
                return;
            }
            file_list = temp;
        }
    }

    // 根据选择的类型排序
    switch (sort_type) {
        case 1: // 按大小排序
            qsort(file_list, count, sizeof(FileInfo), compare_by_size);
            break;
        case 2: // 按修改时间排序
            qsort(file_list, count, sizeof(FileInfo), compare_by_mtime);
            break;
        default: // 默认不排序
            break;
    }

    // 输出排序后的文件列表
    for (int i = 0; i < count; i++) {
        show_file_info(file_list[i].filename, &file_list[i].stat_buf);
    }

    // 释放资源
    free(file_list);
    closedir(dir_ptr);
}

// 主函数:解析命令行参数,调用核心逻辑
int main(int argc, char *argv[]) {
    char *dir = "."; // 默认当前目录
    int sort_type = 0; // 0:不排序,1:按大小,2:按修改时间

    // 解析命令行参数:-s按大小,-t按时间,可指定目录
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-s") == 0) {
            sort_type = 1;
        } else if (strcmp(argv[i], "-t") == 0) {
            sort_type = 2;
        } else {
            dir = argv[i];
        }
    }

    do_ls(dir, sort_type);
    return 0;
}

关键逻辑说明

  1. FileInfo结构体:把每个文件的文件名、大小、修改时间和完整stat信息打包在一起,排序时直接操作数组,避免重复调用stat,提升效率。
  2. 自定义比较函数:qsort()需要一个返回int的比较规则,我们实现了两种:
    • 按大小排序:比较st_size字段,返回值控制升序/降序
    • 按时间排序:比较st_mtime字段,同样可以通过反转返回值实现降序
  3. 目录遍历与数组扩容:跳过.和..避免无效处理;数组初始容量设为10,满了就用realloc扩容,兼顾内存效率和灵活性。
  4. 命令行参数支持:可以通过-s指定按大小排序,-t指定按修改时间排序,还能直接传入目录路径(比如./my_ls -t /home)。

内容的提问来源于stack exchange,提问作者liquidOfficer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:56:19