实现ls与改进
实现ls
ls伪代码:
- 打开目录文件
- 针对目录文件
- 读取目录条目
- 显示文件名
- 关闭文件目录文件
查询ls功能:
代码实现:
源代码:
点击查看代码
#include <stdio.h> #include <dirent.h> #include <sys/types.h> void myls(char []); int main(int ac,char * av[]){ if (ac == 1) { myls("."); } else { while (--ac) { ++av; myls(*av); } } return 0; } void myls(char dirname[]){ DIR *dir_ptr; struct dirent *direntp; if ((dir_ptr = opendir(dirname)) == NULL) { fprintf(stderr, "ls1 cannot open %s\n",dirname); } else { while ((direntp = readdir(dir_ptr)) != NULL) printf("%s ", direntp->d_name); printf("\n"); closedir(dir_ptr); } }
码云链接:
myls.c · 魏赫/C语言实现stat_ls_who命令 - 码云 - 开源中国 (gitee.com)
运行结果:
对比ls:
改进ls的实现:
ls的改进中的问题:
- 排序:
- 文件名读入数组
- qsort()排序
- 分栏:
- 文件名读入数组
- 计算列宽和行数
- .和..
- 加入-a选项
- 没有-a,不显示隐藏文件
- l(会显示详细信息)
- 功能不同
- 单独实现
- 如何读取文件属性
- man 2 stat查看stat结构体的详细信息
st_size
:所占字节数st_nlink
:文件链接数st_mtime
:文件最后修改时间(time_t->ctime日历时间格式)st_mode
:文件类型和许可权限(模式转化为字符 user group other)
改进代码:
点击查看代码
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <errno.h> #include <dirent.h> #include <string.h> #include <linux/limits.h> #include <pwd.h> #include <grp.h> #include <time.h> #define PARAM_NONE 0 //无参数 #define PARAM_A 1 //-a #define PARAM_L 2 //-l #define MAXROWLEN 80 //一行最多显示的字符数 int g_leave_len = MAXROWLEN; //一行是剩余长度,用于输出对齐 int g_maxlen; //存放某目录下最长文件名的长度 void my_error(const char *errstring, int line) { fprintf(stderr, "line:%d", line); perror(errstring); exit(1); } //打印单个文件,且没有-l参数 void display_single(char *name) { int i, len; //如果本行不足以打印一个文件名则换行 if (g_leave_len < g_maxlen) { printf("\n"); g_leave_len = MAXROWLEN; } len = strlen(name); len = g_maxlen - len; printf("%-s", name); for (i = 0; i < len; i++) { printf(" "); } printf(" "); g_leave_len = g_leave_len - g_maxlen - 2; } /*获取文件属性并打印*/ void display_attribute(struct stat buf, char *name) { char buf_time[32]; struct passwd *psd; struct group *grp; //获取文件类型 if (S_ISLNK(buf.st_mode)) printf("1"); else if (S_ISREG(buf.st_mode)) printf("-"); else if (S_ISDIR(buf.st_mode)) printf("d"); else if (S_ISCHR(buf.st_mode)) printf("c"); else if (S_ISBLK(buf.st_mode)) printf("b"); else if (S_ISFIFO(buf.st_mode)) printf("f"); else if (S_ISSOCK(buf.st_mode)) printf("s"); //获取文件权限 if (buf.st_mode & S_IRUSR) printf("r"); else printf("-"); if (buf.st_mode & S_IWUSR) printf("w"); else printf("-"); if (buf.st_mode & S_IXUSR) printf("x"); else printf("-"); if (buf.st_mode & S_IRGRP) printf("r"); else printf("-"); if (buf.st_mode & S_IWGRP) printf("w"); else printf("-"); if (buf.st_mode & S_IXGRP) printf("x"); else printf("-"); if (buf.st_mode & S_IROTH) printf("r"); else printf("-"); if (buf.st_mode & S_IWOTH) printf("w"); else printf("-"); if (buf.st_mode & S_IXOTH) printf("x"); else printf("-"); printf(" "); //根据uid和gid获取文件所有者的用户名于组名 psd = getpwuid(buf.st_uid); grp = getgrgid(buf.st_gid); printf("%4d", buf.st_nlink); printf("%-8s", psd->pw_name); printf("%-9s", grp->gr_name); printf("%6d", buf.st_size); strcpy(buf_time, ctime(&buf.st_mtime)); //将格林位置时间转化成正常时间格式 buf_time[strlen(buf_time) - 1] = 0; printf(" %s", buf_time); } //根据flag参数显示文件内容,调用display_single或者display_attribute void display(int flag, char *pathname) { int i, j; struct stat buf; char name[NAME_MAX + 1]; for (i = 0, j = 0; i < strlen(pathname); i++) { if (pathname[i] == '/') { j = 0; } else name[j++] = pathname[i]; } name[j] = 0; if (lstat(pathname, &buf) == -1) { my_error("stat", __LINE__); } if (flag == PARAM_NONE) { if (name[0] != '.') //不显示隐藏文件 { display_single(name); } } else if (flag == PARAM_A) { display_single(name); } else if (flag == PARAM_L) { if (name[0] != '.') { display_attribute(buf, name); printf(" %-s\n", name); } } else if (flag == (PARAM_A | PARAM_L)) { display_attribute(buf, name); printf(" %-s\n", name); } } void display_dir(int flag_param, const char *path) { DIR *dir; struct dirent *dirent; char filenames[256][PATH_MAX + 1], temp[PATH_MAX + 1]; int count = 0; //总共有多少个文件 if ((dir = opendir(path)) == NULL) { my_error("opendir", __LINE__); } //获取文件总数和最长文件名 while ((dirent = readdir(dir)) != NULL) { if (g_maxlen < strlen(dirent->d_name)) g_maxlen = strlen(dirent->d_name); count++; } closedir(dir); if (count > 256) my_error("文件太多超过了256个", __LINE__); int i, j, len = strlen(path); //获取目录下所有的文件名 dir = opendir(path); for (i = 0; i < count; i++) { dirent = readdir(dir); if (dirent == NULL) { my_error("readdir", __LINE__); } strncpy(filenames[i], path, len); filenames[i][len] = 0; strcat(filenames[i], dirent->d_name); filenames[i][len + strlen(dirent->d_name)] = 0; } //对文件名进行排序 for (i = 0; i < count - 1; i++) for (j = i + 1; j < count - 1; j++) { if (strcmp(filenames[i], filenames[j]) > 0) { strcpy(temp, filenames[j]); strcpy(filenames[j], filenames[i]); strcpy(filenames[i], temp); } } for (i = 0; i < count; i++) display(flag_param, filenames[i]); closedir(dir); //没有-l的话打印一个换行符 if ((flag_param & PARAM_L) == 0) printf("\n"); } int main(int argc, char **argv) { int i, j, k; int num; //记录-的个数 char path[PATH_MAX + 1]; char param[32]; // 保存命令行参数 int flag_param = PARAM_NONE; struct stat buf; j = 0; num = 0; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { for (k = 1; k < strlen(argv[i]); k++) { param[j] = argv[i][k]; j++; } num++; } } //现在只支持-a和-l参数 for (i = 0; i < j; i++) { if (param[i] == 'a') { flag_param |= PARAM_A; } else if (param[i] == 'l') { flag_param |= PARAM_L; } else { printf("错误的参数:%c\n", param[i]); exit(1); } } param[j] = 0; //如果没有输入文件名或者目录,就显示当前目录 if ((num + 1) == argc) { strcpy(path, "./"); path[2] = 0; display_dir(flag_param, path); return 0; } i = 1; for (i = 1; i < argc; i++) { if (argv[i][0] != '-') { strcpy(path, argv[i]); if (stat(path, &buf) == -1) my_error("stat", __LINE__); if (S_ISDIR(buf.st_mode)) { //判断目录是否以/结尾 if (path[strlen(argv[i]) - 1] != '/') { path[strlen(argv[i])] = '/'; path[strlen(argv[i] + 1)] = 0; } else path[strlen(argv[i])] = 0; display_dir(flag_param, path); } else { display(flag_param, path); } } } return 0; }
码云链接:
myls+.c · 魏赫/C语言实现stat_ls_who命令 - Gitee.com
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~