真是悲剧,看错了题目的意思,自己实现了一个 ls -l 命令。后来发现 C 可以直接调用系统命令。。。
记录一下自己如何模拟 ls 命令。。
ls -l 长格式的输出结果如下:
第一个字符代表的是该文件的类型:-(普通文件)、d(目录文件)、b(块设备文件)、c(字符设备文件)、p(管道文件)、l(符号链接文件)
之后的9个字符分为三组,分别是:文件所有者、同一用户组、其他用户。其中的三个字符分别的意思是:r(可读)、w(可写)、x(可执行)
之后可能出现的实心点不知道是什么意思。数字是对于普通文件似乎是硬链接的个数。
然后剩下的是所有者、所在用户组,文件大小,文件最新修改时间、文件名
首先,获取一个目录下的所有文件信息得用 opendir、readdir、closedir 这三个函数:
DIR * dp;
struct dirent *filename;
opendir(path);
while((filename=readdir(dp) != NULL)
{
printf("filename %s\n", filename->d_name);
}
closedir(dp);
其中,dirent 的结构如下:
#include <dirent.h>
struct dirent
{
long d_ino; /* inode number 索引节点号 */
off_t d_off; /* offset to this dirent 在目录文件中的偏移 */
unsigned short d_reclen; /* length of this d_name 文件名长 */
unsigned char d_type; /* the type of d_name 文件类型 */
char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长255字符 */}
而要获得文件其他更详细的信息,就得调用 stat 函数。
#include<unistd.h>
int stat(const char * file_name,struct stat *buf);
stat 函数的作用是将 file_name 指的文件状态复制到 buf 中。使用方法是:
struct stat buf;
while (filename=readdir(dp))
{
stat(filename->d_name, &buf);
do_somethine(buf);
}
struct stat 的定义如下:
#include<sys/stat.h>
struct stat
{
dev_t st_dev; /* device 文件的设备编号 */
ino_t st_ino; /* inode 文件的inode */
mode_t st_mode; /* protection 文件的类型和存取的权限 */
nlink_t st_nlink; /* number of hard links 连到该文件的硬连接数目,刚建立的文件值为1 */
uid_t st_uid; /* user ID of owner 文件所有者的用户识别码 */
gid_t st_gid; /* group ID of owner 文件所有者的组识别码 */
dev_t st_rdev; /* device type 若此文件为装置设备文件,则为其设备编号 */
off_t st_size; /* total size, in bytes 文件大小,以字节计算 */
unsigned long st_blksize; /* blocksize for filesystem I/O 文件系统的 I/O 缓冲区大小 */
unsigned long st_blocks; /* number of blocks allocated 占用文件区块的个数,每一区块大小为512个字节 */
time_t st_atime; /* time of lastaccess 文件最近一次被存取或被执行的时间 */
time_t st_mtime; /* time of last modification 文件最后一次被修改的时间 */
time_t st_ctime; /* time of last change i-node最近一次被更改的时间 */
};
/* 其中有一下宏定义可以检查这些类型 */
if(S_ISLNK(st_mode)) printf("为符号连接\n");
if(S_ISREG(st_mode)) printf("为一般文件\n");
if(S_ISDIR(st_mode)) printf("为目录\n");
if(S_ISCHR(st_mode)) printf("为字符装置文件\n");
而文件的读写权限存储在 st_mode 变量二进制中的低9位。
而文件的所有者和所在用户组可以通过 stat 结构体中的 st_uid 和 st_gid 来获取。比如所有者的信息可以通过 getpwuid 函数获得:
// getpwuid 函数的定义
struct passwd * getpwuid(uid_t uid);
// 其中的 passwd 结构体定义如下
struct passwd
{
char * pw_name; /* Username, POSIX.1 用户名 */
char * pw_passwd; /* Password 用户加密后的密码 */
__uid_t pw_uid; /* User ID, POSIX.1 用户的ID */
__gid_t pw_gid; /* Group ID, POSIX.1 所在用户组ID */
char * pw_gecos; /* Real Name or Comment field 所有者的详细用户名 */
char * pw_dir; /* Home directory, POSIX.1 所有者主目录 */
char * pw_shell; /* Shell Program, POSIX.1 所有者使用的shell */
};
最后就是时间信息。时间信息我使用的是 stat 结构体中的 st_mtime ,可以通过 localtime 进行格式化:
// localtime 函数的定义
struct tm *localtime(const time_t * timep);
// tm 结构体的定义
struct tm
{
int tm_sec; /* 目前秒数 */
int tm_min; /* 目前分数 */
int tm_hour; /* 午夜算起的时数,范围为0-23 */
int tm_mday; /* 目前月份的日数,范围01-31 */
int tm_mon; /* 目前月份 */
int tm_year; /* 从1900 年算起至今的年数 */
int tm_wday; /* 一星期的日数,从星期一算起 */
int tm_yday; /* 从今年1月1日算起至今的天数 */
int tm_isdst; /* 日光节约时间的旗标 */
};
通过这些,基本就可以模拟 ls 命令了。