IO进程 day03
IO进程 day03
- 7. 目录操作函数
- 7.1. opendir/closedir
- 7.2. readdir
- 7.3. chdir
- 7.4. stat
- 基本用法
- 获取文件类型
- 获取文件权限
- 其他的结构体成员的使用
- 8. 库
- 8.1. 库的概念
- 8.2. 库的分类
- 8.3. 静态库制作
- 8.4. 动态库的制作
- 9. 进程
- 9.1. 进程和程序的区别
7. 目录操作函数
函数功能 函数名 打开目录 opendir 关闭目录 closedir 读目录 readdir 修改文件路径 chdir 获取文件属性 stat
7.1. opendir/closedir
opendir
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
功能:打开目录文件
参数:目录流,指向打开的目录文件
返回值:
成功返回目录流指针
失败返回NULL,更新errno
closedir
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
功能:关闭目录文件
参数:目录流,指向开的的目录文件
返回值:成功返回0,失败返回-1,并且更新errno
7.2. readdir
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
功能:读取目录文件内容
参数:目录流,指向打开的目录文件
返回值:
成功返回结构体指针,读到文件结尾返回NULL
失败返回NUL
结构体:
struct dirent
{ino_t dino; // 文件的inodeoff_t d_off; unsigned short d_reclen;unsigned char d_type; //文件类型,并不支持所有文件类型char d_name[256]; // 文件名
};
练习
实现ls -a的功能
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>int main ()
{DIR *dirp = NULL; struct dirent* dire = NULL;// 打开文件dirp = opendir("./");if(dirp == NULL){perror("open err");return EOF;}// 读取文件while(dire = readdir(dirp))pritnf("%s\t", dire->d_name);closedir(dirp);return 0;
}
7.3. chdir
#include <unistd.h>
int chdir(const char* path);
功能:改变当前工作路径
参数:path:修改之后的路径
返回值:成功返回0,失败返回-1,更新errno
注意
只有程序走到该函数之后,工作路径从程序所在路径改成path指向的路径,修改创建文件都在修改之后的路径下实现
7.4. stat
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *buf);
功能:获取文件属性
参数:
pathname:文件
buf:获取到属性存放的位置
返回值:成功返回0,失败返回-1,并且更新errno
struct stat
{dev_t st_dev; // 包含文件的设备IDino_t st_ino; // 文件的inode号mode_t st_mode; // 文件的类型和权限nlink_t st_nlink; // 硬链接数uid_t st_uid; // 用户IDgid_t st_gid; // 组IDdev_t st_rdev;off_t st_size; //大小blksize_t st_blksize; // 文件系统IO块的大小blkcnt_t st_blocks; // 512b的分配数量struct timespec st_atim; // 最后一次访问的时间struct timespec st_mtim; // 最后一次修改的时间struct timespec st_ctim; // 最后一次状态改变的时间
}
基本用法
获取文件的inode号
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>int main(int argc, char const *argv[])
{DIR *dirp = NULL;struct dirent *dir = NULL;struct stat sb;// 打开文件dirp = opendir("./");if (dirp == NULL){perror("open err");return EOF;}// 读取文件while (dir = readdir(dirp)){if (stat(dir->d_name, &sb) == -1){perror("stat err");return -1;}printf("%ld %s ", sb.st_ino, dir->d_name);}printf("\n");closedir(dirp);return 0;
}
获取文件类型
- man 7 inode:The following mask values are defined for the file type
- 对于文件类型,定义了一下掩码值(8进制)
宏名 | 掩码值 | 文件类型 |
---|---|---|
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—字符设备文件 |
S_IFIFO | 0010000 | FIFO—管道文件 |
- 先通过stat获取文件的类型和权限
#include <stdio.h>
#include <sys/types>
#include <sys/stat.h>
#include <unistd.h>int main ()
{// 通过stat获取文件属性struct stat sb ;if(stat(argv[1], &sb) == -1){perror("stat err");return EOF;}pritnf("mode = %o\n", sb.st_mode); // 掩码是8进制,mode转换成8进制
}
- 使用方法
stat(pathname, &sb);
if((sb.st_mode & S_IFMT) == S_IFREG)printf("普通文件");
- 换一种写法,通过宏来直接得到真值或假值
宏名 | 判断文件类型 |
---|---|
S_ISREG(mode) | regular file—普通文件 |
S_ISDIR(mode) | directory—目录文件 |
S_ISCHR(mode) | character device—字符设备文件 |
S_ISBLK(mode) | block device—块设备文件 |
S_ISFIFO(mode) | FIFO—管道文件 |
S_ISLNK(mode) | symbolic link—连接文件 |
S_ISSOCK(mode) | socket—套接字文件 |
stat(pathname, &sb);
if(S_ISREG(sb.st_mode))printf("regular file");
获取文件权限
对于文件权限,也有相应的掩码
宏名 | 掩码 | 权限 |
---|---|---|
S_IRUSR | 00400 | 用户的读权限 |
S_IWUSR | 00200 | 用户的写权限 |
S_IXUSR | 00100 | 用户的执行权限 |
S_IRGRP | 00040 | 同组的读权限 |
S_IWGRP | 00020 | 同组的写权限 |
S_IXGRP | 00010 | 同组的执行权限 |
S_IROTH | 00004 | 其他用户的读权限 |
S_IWOTH | 00002 | 其他用户的写权限 |
S_IXOTH | 00001 | 其他用户的执行权限 |
需要哪一项权限就用mode位与哪一项权限的掩码
if(sb.st_mode & S_IRUSR)printf("r");
其他的结构体成员的使用
- 通过用户id获取用户名
#include <pwd.h>
struct passwd* getpwuid(uid_t uid);
struct passwd
{char *pw_name; // 用户名char *pw_passwd; // 用户密码uid_t pw_uid; // 用户IDgid_t pw_gid; // 组IDchar *pw_gecos; // 用户信息char *pw_dir; // 家目录char *pw_shell;
};
struct passwd* user_name = NULL;
user_name = getpwuid(sb.st_uid);
user_name->pw_name;
- 通过组ID获取组名
#include <grp.h>
struct group *getgrgid(gid_t gid);
struct group
{char *gr_name; // 组名char *gr_passwd; // 组密码gid_t gr_gid; // 组IDchar **gr_mem; // 组内成员
};
- 转换时间格式
将时间转换成字符串的形式表示
#include <time.h>
char *ctime(const time_t *timep);
// 将时间转换成为"Wed Jun 30 21:49:08 1993\n"的格式
8. 库
8.1. 库的概念
把一些的常用的函数的目标文件打包到一起,提供相应的函数接口。本质上是一种可执行代码的二进制形式
8.2. 库的分类
静态库 | 动态库 | |
---|---|---|
编译 | 在编译时会被连接到目标代码中 | 在程序运行时才会被载入到程序中 |
优点 | 运行时不需要加载库,运行速度快 运行时不依赖库文件,可移植性高 | 程序在执行时加载动态库,体积较小 |
缺点 | 静态库中的代码复制到程序中,所以体积大 | 运行时需要加载库文件,运行速度较慢 运行时依赖库文件,可移植性较差 |
库升级 | 静态库升级之后程序需要重新编译链接 | 动态库升级之后不需要重新编译程序 |
Linux | .a | .so |
Windows | .lib | .dll |
8.3. 静态库制作
-
将源文件编译生成目标文件
gcc -c xxx.c -o xxx.o
-
创建静态库,用ar命令,将.o文件生成.a文件
ar crs libxxx.a xxx.o
-
静态库的使用
gcc main.c -L指定库的路径 -l指定的库名
8.4. 动态库的制作
- 创建一个与地址无关的目标文件
gcc -fPIC -c xxx.c -o xxx.o
- 创建动态库
gcc -shared -o libxxx.so xxx.o
- 测试使用
gcc xxx.c -L指定路径 -l指定的库名 - 执行
- 错误原因:动态库被加载时会优先从/lib下寻找库文件
- 解决办法:
1. 把库文件拷贝到/usr/lib下
sudo cp libxxx.so /sur/lib
2. 在LD_LIBRARY_PATH 环境变量中加上库所在的路径
export LD_LIBRARY_PAYH = $LD_LIBRARY_PATH:.
只在当前终端有效
3. 添加/etc/ld.so.conf.d/*.conf文件
9. 进程
9.1. 进程和程序的区别
程序:
1. 编译好的可执行的二进制文件
2. 存放在磁盘上,指令和数据的有序集合(文件)
3. 静态的,没有任何执行的概念
进程:
1. 独立的可调度的任务
2. 执行一个程序所分配的资源的总称
3. 进程是程序一次完整执行过程
4. 进程是动态的,包括创建,调度,执行,消亡
5. 进程活动在内存上,断电会丢失