- 实例要求:
- 使用
文件IO
的接口在一个目录
下,实现Linux
命令“ls -l
”的功能; - 实例分析:
- 正常使用“
ls -l
”命令,会出现以下内容:
/*
- rwxrw-rw- 1 linux linux 26 10月2 14:31 x.txt
文件类型 所属用户的权限\所属组的权限\其他人的权限 硬链接个数 所属用户 所属组 大小(字节) 时间戳 文件名
*/
- 相关的文件IO接口函数如下:
- opendir函数:
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
/*
功能:打开一个目录文件
参数name:目录名
返回值:
成功: 目录指针
失败: NULL 重置错误码
*/
- readdir函数:
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
/*
功能:读取目录下的内容
参数:目录指针
返回值:
成功: dirent结构体指针
失败: NULL 重置错误码
*/
// dirent结构体指针
struct dirent {
ino_t d_ino; /* 读到的文件的inode号 */
off_t d_off; /* 无需关注 */
unsigned short d_reclen; /* 这个结构体的大小 不是文件的大小 */
unsigned char d_type; /* 文件类型 */
DT_BLK This is a block device.
DT_CHR This is a character device.
DT_DIR This is a directory.
DT_FIFO This is a named pipe (FIFO).
DT_LNK This is a symbolic link.
DT_REG This is a regular file.
DT_SOCK This is a UNIX domain socket.
char d_name[256]; /* 文件名 */
};
- closedir函数:
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
/*
功能:关闭一个目录
参数dirp:目录指针
返回值:
成功: 0
失败: -1 重置错误码
*/
- stat函数:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
/*
功能:
获取文件的属性信息
参数:
pathname:文件的路径和名字
statbuf:用来保存文件属性的结构体
返回值:
成功 0
失败 -1 重置错误码
*/
//文件属性的结构体
struct stat {
dev_t st_dev; /* 文件所在磁盘的设备号 */
ino_t st_ino; /* inode号 */
mode_t st_mode; /* 文件的类型和访问模式 */
//S_IFMT 0170000 文件类型的掩码
//S_IFSOCK 0140000 socket
//S_IFLNK 0120000 symbolic link
//S_IFREG 0100000 regular file
//S_IFBLK 0060000 block device
//S_IFDIR 0040000 directory
//S_IFCHR 0020000 character device
//S_IFIFO 0010000 FIFO
if((S_IFMT & st_mode) == S_IFREG){//注意优先级问题
printf("普通文件\n");
}
//或者用下面的宏判断
if(S_ISREG(m)){
printf("普通文件\n");
}
//st_mode & 0777 == 文件的权限
nlink_t st_nlink; /* 硬链接的个数 */
uid_t st_uid; /* 所属用户的id */
gid_t st_gid; /* 所属组的id */
dev_t st_rdev; /* 设备号 字符设备文件或者块设备文件使用 */
off_t st_size; /* 总大小 单位字节 */
blksize_t st_blksize; /* 块的大小 */
blkcnt_t st_blocks; /* 块的数量 */
struct timespec st_atim; /* 最后一次访问的时间 */
struct timespec st_mtim; /* 最后一次修改的时间 */
struct timespec st_ctim; /* 最后一次状态改变的时间 */
//下面的宏定义是为了方便获取时间戳里的秒数的
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
- getpwuid函数:
#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
/*
功能:
根据uid获取用户信息
参数:
uid: 用户id
返回值:
成功: 用户信息结构体
失败: NULL 重置错误码
*/
//用户信息结构体
struct passwd {
char *pw_name; /* username */
char *pw_passwd; /* user password */
uid_t pw_uid; /* user ID */
gid_t pw_gid; /* group ID */
char *pw_gecos; /* user information */
char *pw_dir; /* home directory */
char *pw_shell; /* shell program */
};
- getgrgid函数:
#include <sys/types.h>
#include <grp.h>
struct group *getgrgid(gid_t gid);
/*
功能:
根据gid获取组信息
参数:
gid: 组id
返回值:
成功 组信息结构体
失败 NULL 重置错误码
*/
struct group {
char *gr_name; /* group name */
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /* NULL-terminated array of pointers to names of group members */
};
- sprintf函数:
#include <stdio.h>
int sprintf(char *str, const char *format, ...);
/*
功能:
将格式化的信息写入str指向的缓冲区中
参数:
str: 自定义的缓冲区的首地址
format: 格式
...: 可变参
返回值:
成功: 格式化的字符的个数
失败: 小于0的值
*/
- 示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
//所属用户权限宏定义
#define U_R 0400
#define U_W 0200
#define U_X 0100
//所属组权限宏定义
#define G_R 0040
#define G_W 0020
#define G_X 0010
//其他人权限宏定义
#define O_R 0004
#define O_W 0002
#define O_X 0001
int main(int argc, const char *argv[])
{
//入参合理性检查
if (2 != argc)
{
printf("Usage : %s dir_name\n", argv[0]);
return -1;
}
// 打开目录
DIR *my_dir = opendir(argv[1]);
if (NULL == my_dir)
{
perror("opendir error");
return -1;
}
//文件的类型
char type = '-';
//所属用户权限赋初值
char u_r = '-';
char u_w = '-';
char u_x = '-';
//所属组权限赋初值
char g_r = '-';
char g_w = '-';
char g_x = '-';
//其他人权限赋初值
char o_r = '-';
char o_w = '-';
char o_x = '-';
int nlink = 0;
char u_name[64] = {0};
char g_name[64] = {0};
int size = 0;
char date[128] = {0};
char path_name[512] = {0};
struct tm *p = NULL;
struct stat lk;
struct dirent *dir = NULL;
int mode = 0;
while (NULL != (dir = readdir(my_dir)))
{
//过滤隐藏文件
if ('.' == *(dir->d_name))
{
continue;
}
//文件类型
switch (dir->d_type)
{
case DT_BLK:
type = 'b';
break;
case DT_SOCK:
type = 's';
break;
case DT_FIFO:
type = 'p';
break;
case DT_REG:
type = '-';
break;
case DT_LNK:
type = 'l';
break;
case DT_CHR:
type = 'c';
break;
case DT_DIR:
type = 'd';
break;
}
//数组清零
memset(path_name, 0, sizeof(path_name));
//组装路径
sprintf(path_name, "%s/%s", argv[1], dir->d_name);
if (stat(path_name, &lk))
{
perror("stat error");
return -1;
}
u_r = '-';
u_w = '-';
u_x = '-';
g_r = '-';
g_w = '-';
g_x = '-';
o_r = '-';
o_w = '-';
o_x = '-';
// 文件权限
mode = lk.st_mode & 0777;
if (mode & U_R)
{
u_r = 'r';
}
if (mode & U_W)
{
u_w = 'w';
}
if (mode & U_X)
{
u_x = 'x';
}
if (mode & G_R)
{
g_r = 'r';
}
if (mode & G_W)
{
g_w = 'w';
}
if (mode & G_X)
{
g_x = 'x';
}
if (mode & O_R)
{
o_r = 'r';
}
if (mode & O_W)
{
o_w = 'w';
}
if (mode & O_X)
{
o_x = 'x';
}
//硬链接的个数
nlink = lk.st_nlink;
//所属用户名
strcpy(u_name, getpwuid(lk.st_uid)->pw_name);
//所属组名
strcpy(g_name, getgrgid(lk.st_gid)->gr_name);
//文件的大小(字节)
size = lk.st_size;
//时间戳(最后一次修改的时间)
p = localtime(&(lk.st_mtime));
sprintf(date, "%2d月%2d %02d:%02d", p->tm_mon + 1, \
p->tm_mday, p->tm_hour, p->tm_min);
//输出文件的基本内容
printf("%c%c%c%c%c%c%c%c%c%c %d %s %s %7d %s %-s\n",\
type, u_r, u_w, u_x, g_r, g_w, g_x, o_r, o_w, o_x, nlink,\
u_name, g_name, size, date, dir->d_name);
}
// 关闭目录
closedir(my_dir);
return 0;
}
- 运行结果:
linux@ubuntu:~$ ./a.out ./
-rw-rw-r-- 1 linux linux 730 10月 1 22:44 k1.c
-rw-rw-r-- 1 linux linux 26 10月 1 22:40 k2.txt
-rwxrwxr-x 1 linux linux 12984 10月 2 19:31 a.out
-rw-rw-r-- 1 linux linux 4078 10月 2 19:17 ls-l.c
drwxrwxr-x 2 linux linux 4096 10月 2 18:59 k3
linux@ubuntu:~$ ls -l
总用量 32
-rwxrwxr-x 1 linux linux 12984 10月 2 19:31 a.out
-rw-rw-r-- 1 linux linux 730 10月 1 22:44 k1.c
-rw-rw-r-- 1 linux linux 26 10月 1 22:40 k2.txt
drwxrwxr-x 2 linux linux 4096 10月 2 18:59 k3
-rw-rw-r-- 1 linux linux 4078 10月 2 19:17 ls-l.c
- 本示例代码,仅供参考;