首先展示ls -l的表现效果
无视最上面的总用量,我们可以看出,我们需要输出:文件类型、文件权限、硬链接数、当前用户名,当前用户组,文件大小,文件最后创建时间(月日、时分)以及文件名
为了实现功能,我们需要大量头文件
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<dirent.h>
#include<dirent.h>
#include<errno.h>
#include<pwd.h>
#include<grp.h>
#include<time.h>
#include<stdlib.h>
#include"stath.h"
首先打开目录,我们采用外部传参的方式
//打开目录
DIR *dp = opendir(argv[1]);
if(NULL == dp)
{
printf("line%d,目录打开失败", __LINE__);
perror("opendir");
return -1;
}
定义指针rp,用来获取读取到的目录信息
struct dirent *rp = NULL;
//指针原型:struct dirent *readdir(DIR *dirp);
目录中可能有不止一个文件,所以用死循环包裹住。用指针rp接收目录信息,以为ls -l无法显示隐藏信息,所以我们还需要摘除隐藏信息(隐藏信息以 ' . ' 开头)
rp = readdir(dp);
//判断文件读完还是出错
if(NULL == rp)
{
if(0 == errno) //目录读到结尾
{
break;
}
else
{
printf("line:%d", __LINE__);
perror("readdir");
return -1;
}
}
if(rp->d_name[0] == '.')//筛掉隐藏文件
continue;
至此,我们就成功筛选出了符合条件的信息
定义结构体变量buf,接收目录内的文件信息
struct stat buf; //接受文件信息
//struct stat *statbuf:该指针指向的内存空间中会存储获取到的文件属性;
struct stat结构体的原型如下
struct stat *statbuf:该指针指向的内存空间中会存储获取到的文件属性;
返回值:
成功,返回0;
失败,返回-1,更新errno;
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* Inode number */
mode_t st_mode; /* File type and mode */ 文件类型以及文件权限
nlink_t st_nlink; /* Number of hard links */ 硬链接数
uid_t st_uid; /* User ID of owner */ 用户的uid
gid_t st_gid; /* Group ID of owner */ 组用户的gid
dev_t st_rdev; /* Device ID (if special file) */
off_t st_size; /* Total size, in bytes */ 文件大小
blksize_t st_blksize; /* Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512B blocks allocated*/
/* Since Linux 2.6, the kernel supports nanosecond
precision for the following timestamp fields.
For the details before Linux 2.6, see NOTES. */
struct timespec st_atim; /* Time of last access */ 文件最后一次访问的时候
struct timespec st_mtim; /* Time of last modification */ 文件最后一次被修改的时间
struct timespec st_ctim; /* Time of last status change */ 最后一次改变状态的时间(创建时间)
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
因为stat要的是文件以及路径,但rp->neme只有文件名。故,如果输入的文件不在当前路径下,stat将无法获取文件信息,所以,我们定义一个字符串数组来添加路径。
char pathname[99];
strcpy(pathname, argv[1]);
strcat(pathname, rp->d_name);
获取文件,以为stat函数要的是指针变量,如果我们采用的是结构体指针,则需要malloc手动事情空间,故,我在上面采用了结构体普通变量的方式,来偷懒。
//用地址规避malloc偷懒
if( stat(pathname, &buf) < 0 )
{
printf("文件获取失败\n");
perror("stat");
return -1;
}
1:文件类型获取
与文件权限在一个变量内存储:mode_t st_mode;
man手册内介绍了一个自带函数
mode_t m;
m = buf.st_mode; //给m赋值
get_fileType(m); //文件类型
//mode_t st_mode; /* File type and mode */ 文件类型以及文件权限
int get_fileType(mode_t m) //man手册自带函数
{
switch (m & S_IFMT)
{
case S_IFBLK: printf("b"); break;
case S_IFCHR: printf("c"); break;
case S_IFDIR: printf("d"); break;
case S_IFIFO: printf("p"); break;
case S_IFLNK: printf("l"); break;
case S_IFREG: printf("-"); break;
case S_IFSOCK: printf("s"); break;
default: printf("unknown?\n"); break;
}
return 0;
}
2:文件权限
文件权限在变量内表现为一个二进制数
000 000 000,分别代表wrxwrxwrx,所以,当,我们拿100 000 000去和给定的权限值按位与,如果第一位不是1,则结果为0,自然,我们就知道了,第一个位置:写权限,是没有的。我们拿一个循环包裹,让1一位一位移动,就可以直到每一个权限的情况
自定义函数:
void get_permission(mode_t m)
{
int i=0;
for(i=8; i>=0; i--)
{
if( (m & (1<<i)) == 0) //求出对应位置是0还是1
{
printf("-");
continue;
}
//能运行到当前位置则说明相应位置不为0
switch(i%3)
{
case 2:
printf("r");
break;
case 1:
printf("w");
break;
case 0:
printf("x");
break;
}
}
return ;
}
3:硬链接数
//硬链接数
printf(" %ld ", buf.st_nlink);
4:当前用户名
采用自带函数:getpwuid()函数
函数原型:struct passwd *getpwuid(uid_t uid);
//当前用户
struct passwd *pwd = NULL;
pwd = getpwuid(buf.st_uid);
if(NULL == pwd)
{
printf("getpwuid failed\n");
return -1;
}
printf("%s ",pwd->pw_name);
5:当前用户组
//文件所属组用户名
struct group *gp = NULL;
gp = getgrgid(buf.st_gid);
if(NULL == gp)
{
printf("getgrgid failed\n");
return -1;
}
printf("%s ",gp->gr_name);
6:文件大小
//文件大小
printf("%8ld", buf.st_size);
7:时间
使用buf.st_ctime
使用自定义函数,函数上篇文章写过了,略加修改即可
//时间
void my_time(long ctime)
{
long n = ctime;
struct tm *m = localtime(&n);
printf("%2d月 %d %d:%d ",m->tm_mon+1, m->tm_mday, m->tm_hour, m->tm_min);
}
最后是文件名
//文件名
printf("%s", rp->d_name);
再手动换行
不要忘记关闭目录
以下是完整代码
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<dirent.h>
#include<dirent.h>
#include<errno.h>
#include<pwd.h>
#include<grp.h>
#include<time.h>
#include<stdlib.h>
#include"stath.h"
int main(int argc, const char *argv[])
{
//打开目录
DIR *dp = opendir(argv[1]);
if(NULL == dp)
{
printf("line%d,目录打开失败", __LINE__);
perror("opendir");
return -1;
}
struct dirent *rp = NULL;
while(1)
{
rp = readdir(dp);
//判断文件读完还是出错
if(NULL == rp)
{
if(0 == errno) //目录读到结尾
{
break;
}
else
{
printf("line:%d", __LINE__);
perror("readdir");
return -1;
}
}
if(rp->d_name[0] == '.')//筛掉隐藏文件
continue;
//处理符合条件的文件
struct stat buf; //接受文件信息
//因为stat要的是文件以及路径,但rp->neme只有文件名
//故,如果输入的文件不在当前路径下,stat将无法获取文件信息
//所以,我们定义一个字符串数组来添加路径
char pathname[99];
strcpy(pathname, argv[1]);
strcat(pathname, rp->d_name);
//用地址规避malloc偷懒
if( stat(pathname, &buf) < 0 )
{
printf("文件获取失败\n");
perror("stat");
return -1;
}
//文件类型
mode_t m;
m = buf.st_mode; //给m赋值
get_fileType(m); //文件类型
//文件权限
get_permission(m);
//硬链接数
printf(" %ld ", buf.st_nlink);
//当前用户
struct passwd *pwd = NULL;
pwd = getpwuid(buf.st_uid);
if(NULL == pwd)
{
printf("getpwuid failed\n");
return -1;
}
printf("%s ",pwd->pw_name);
//文件所属组用户名
struct group *gp = NULL;
gp = getgrgid(buf.st_gid);
if(NULL == gp)
{
printf("getgrgid failed\n");
return -1;
}
printf("%s ",gp->gr_name);
//文件大小
printf("%8ld", buf.st_size);
//时间
my_time(buf.st_ctime);
//文件名
printf("%s", rp->d_name);
printf("\n");
}
//关闭目录
closedir(dp);
return 0;
}
函数部分
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<dirent.h>
#include<dirent.h>
#include<errno.h>
#include<pwd.h>
#include<grp.h>
#include<time.h>
#include<stdlib.h>
int get_fileType(mode_t m) //man手册自带函数
{
switch (m & S_IFMT)
{
case S_IFBLK: printf("b"); break;
case S_IFCHR: printf("c"); break;
case S_IFDIR: printf("d"); break;
case S_IFIFO: printf("p"); break;
case S_IFLNK: printf("l"); break;
case S_IFREG: printf("-"); break;
case S_IFSOCK: printf("s"); break;
default: printf("unknown?\n"); break;
}
return 0;
}
void get_permission(mode_t m)
{
int i=0;
for(i=8; i>=0; i--)
{
if( (m & (1<<i)) == 0) //求出对应位置是0还是1
{
printf("-");
continue;
}
//能运行到当前位置则说明相应位置不为0
switch(i%3)
{
case 2:
printf("r");
break;
case 1:
printf("w");
break;
case 0:
printf("x");
break;
}
}
return ;
}
//时间
void my_time(long ctime)
{
long n = ctime;
struct tm *m = localtime(&n);
printf("%2d月 %d %d:%d ",m->tm_mon+1, m->tm_mday, m->tm_hour, m->tm_min);
}
//
头文件:略