实现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