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

