Linux 学习记录23(IO篇+静/动态库+多进程理论)
本文目录
一、文件状态获取(stat)
1. 获取文件属性信息
文件属性包括:
1. 包含文件的设备的ID
2. inode号,文件系统识别文件的唯一标识
3. 文件类型和权限
4. 硬链接号
5. 用户ID
6. 组ID
7. 硬件设备号(如果是特殊文件)
8. 文件大小,以字节为单位
9. 块字节大小
10. 块的个数
11. 最后一次被访问的时间
12. 最后一次权限修改时间
13. 最后一次状态修改时间
函数原型:int stat(const char*pathname,struct stat *statbuf);
功能:获取文件的属性信息
参数1:要获取属性的文件路径
参数2:struct stat: 文件属性结构体指针,该结构体中包含了文件
===================================================================
文件属性结构体指针
struct stat {
dev_t st_dev;/* ID of device containing file */ //包含文件的设备的ID
ino_t st_ino;/* Inode number */ //inode号,文件系统识别文件的唯一标识
mode_t st_mode;/* File type and mode */ //文件类型和权限
nlink_t st_nlink;/* Number of hard links */ //硬链接号
uid_t st_uid;/* User ID of owner */ //用户ID
gid_t st_gid;/* Group ID of owner */ //组ID
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 */ //最后一次状态修改时间
};
2. 文件类型与权限
终端指令:man 7 inode
man手册:
使用结构体的mode_t st_mode参数能够获得文件的类型与权限
- st mode&S_IFMT ------------>能够得到文件类型
S_IFSOCK 套接字文件
S_IFLNK软连接文件
S_IFREG 普通文件
S_IFBLK 块设备文件
S_IFDIR 目录文件
S_IFCHR 字符设备文件
S_IFIFO 管道文件
- 使用函数 ------------>能够得到文件类型
- st_mode&0777 —>得到文件权限
3. 使用函数打印部分文件信息到终端
int main(int argc, char const *argv[])
{
struct stat sb;
/*获取文件属性*/
stat("./01file.txt", &sb);
/*类型*/
switch(sb.st_mode&__S_IFMT)
{
case __S_IFSOCK : printf("flie type: 套接字文件\n"); break;
case __S_IFLNK : printf("flie type: 软连接文件\n"); break;
case __S_IFREG : printf("flie type: 普通文件\n"); break;
case __S_IFBLK : printf("flie type: 块设备文件\n"); break;
case __S_IFDIR : printf("flie type: 目录文件\n"); break;
case __S_IFCHR : printf("flie type: 字符设备文件\n"); break;
case __S_IFIFO : printf("flie type: 管道文件\n"); break;
default : break;
}
/*权限*/
printf("flie mode: %#o\n",sb.st_mode&0777);
/*大小*/
printf("flie size: %ld byte\n", sb.st_size);
/*inode号*/
printf("flie inode ID: %ld\n",sb.st_ino);
return 0;
}
输出>>
flie type: 普通文件
flie mode: 0664
flie size: 155 byte
flie inode ID: 529027
终端查看文件结果:
二、对目录的操作
1. 打开目录
函数原型:DIR *opendir(const char *name);
功能:通过指定的路径打开一个目录
参数1:目录的路径
返回值:成功返回DIR*的目录指针,失败返回NULL并置位错误码
======================================================
2. 读取目录下的内容
函数原型:struct dirent *readdir(DIR *dirp);
功能:通过指定的目录指针读取出一条文件的信息,将信息放置于struct dirent类型的指针中
通过该指针获取文件的信息
参数1:指定的目录指针
返回值:成功返回struct dirent的结构体指针,失败返回NULL并置位错误码
每读取一次向下偏移一次
======================================================
struct dirent {
ino_t d_ino;/* Inode number */ //inode号
off_t d_off;/* Not an offset; see below */ //偏移量
unsigned short d_reclen;/* Length of this record */ //当前文(子目录)件大小
unsigned char d_type;/* Type of file; not supported
by all filesystem types */ //文件类型
char d_name[256]; /* Null-terminated filename */ //文件名
};
========================================================
文件类型:
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.
DT_UNKNOWN-->The file type could not be determined.
3. 关闭目录
函数原型:int closedir(DIR *dirp);
功能:关闭当前目录
参数1:指定的目录指针
返回值:成功返回0,失败返回-1并置位错误码
4. 目录操作的实例
int main(int argc, char const *argv[])
{
DIR* dp;
if((dp=opendir("./"))==NULL)
{
perror("opendir: ");
return -1;
}
struct dirent* tp;
while((tp = readdir(dp)) != NULL)
{
printf("%s\t",tp->d_name);
printf("%c\t",tp->d_type);
printf("%-4d\t",tp->d_reclen);
printf("%ld\t",tp->d_ino);
printf("\r\n");
}
return 0;
}
三、Linux系统中的库
- Linux中的库本质上是一个二进制文件,
由.c文件(不包含main)编译而来
其他程序可以使用该库调用相关的函数- 包含静态库,动态库两种
- 不同操作系统对库的格式有所不同
- windows: xxx.lib=静态库,xxx.dll=动态库两种
- Linux: libxxx.a = 静态库,libxxx.so = 动态库两种
- 由于库是二进制文件,.c文件编译后生成库后,函数的实现过程是看不到的,所以使用库比较安全
使用ldd命令可以查看文件所依赖的头文件
例如 printf函数需要头文件------>#include <stdio.h>
但是该头文件只有函数的声明,
函数的实现在lib.so库中(Linux系统中的动态库)
1. 静态库
将xxx.c文件编译生成的一个库名为.a的二进制文件,当需要使用该库中的某个函数时,直接调用该函数即可,前提是编译时链接了该库
- 动态态:在使用gcc编译时,会将你的我加你和库文件一起生成一个可执行文件,在最终可执行程序在包含了静态库,但是程序体积一般比较大,但是在执行程序时,无需去寻找该库的位置,效率较高
(1. 静态库的创建
- 准备好.c源文件
- 准备好对于的.h头文件
- 准备测试文件
- 编译生成
- 编译测试
命令:gcc -c add.c -o add.o
- 只生成不链接
命令:ar -cr libadd.a add.o
- ar->说明这是静态库的命令
- -c->创建
- -r->允许使用该函数
- 如果使用多个.o文件生成库 ar -crs 库名.a add1.o add2.o…
命令:gcc main.c -L ./ -ladd -I ./
- -L : 指定库的路径
- -l :所需库的名字
- -I :指定头文件的路径
2. 动态库
静态库只,将xxx.c文件编译生成的一个库名为.a的二进制文件,当需要使用该库中的某个函数时,直接调用该函数即可,前提是编译时链接了该库
- 静态:在使用gcc编译时,会将你的我加你和库文件一起生成一个可执行文件,但是程序体积较小,但是在执行程序时,需去寻找该库的位置,效率较低,但是可以由多个文件共享一个文件,动态库又称共享库
(1. 动态库的创建
- 准备好.c源文件
- 准备好对于的.h头文件
- 准备测试文件
- 编译生成
- 测试
- 解决上述错误
- 在命令行指定库的路径:export LD_LIBRARY_PATH=库的路径(仅在当前终端有效)
- 将上述的库放入系统库中(/lib或/usr/lib)
- 更改系统在库的配置文件
命令:gcc -fPIC -c add.c -o add.o
-fPIC:忽略文件位置,生成二进制文件
命令:gcc -shared add.o -o libadd.so
生成动态库,依赖于add.o生成的库名为libadd.so库
命令:gcc -fpIC -shared add.6+c -o libadd.so
上面两条指令可以合成一条指令
四、多进程理论
1. 进程的概念
进程:程序的一次执行过程
- 进程就是正在执行的程序
- 进程是一个动态的过程,
是有生命周期
的,随着经常的创建而出现,随着经常的消亡而销毁- 进程是分配资源的最小单位,每个进程都会拥有自己的0-3G的用户空间,但是共享3–4G的内核空间
- 这0–3G的用户空间又被分为三个部分:
栈区、堆区、静态区
- 进程在内核空间由一个
task struct结构体
表示
2. 进程的内存管理 (重点!!!)
- 每个进程都会分配4G的空间(虚拟内存)
- 每个进程都都拥有独立的0-3G的用户空间,3-4G的内核空间是共享的
3. 程序和进程的区别
进程:进程是动态的,有生命周期,是程序的一次执行过程,每个进程拥有0--3G的用户空间
并且共享3--4G的内核空间
程序:程序是静态的,没有生命周期可言,它是在磁盘上的一个二进制文件
4. 进程的组成
- 进程由三部分组成:进程控制段(PCB)、数据段、程序段
- 进程控制段:是内核空间分配的一个task strut的结构体,包含了一个进程的所有信息: PID、进程的状态、相关寄存器
- 数据段:在进程执行过程中,中间数据存放的位置:.data bss
- 程序段:存放程序允许的代码: text
5. 进程的种类
- 进程一共有三种:交互进程、批处理进程、守护进行
- 交互进程:他是由shel脚本控制,可以直接跟用户进行交互的进程,例如文本编辑器
- 批处理进程:维护了一个队列,被放到该队列中的进程会统一被处理,例如终端执行./a.out
- 守护进程:他是脱离终端而存在,例如服务进程
6. 进程的PID概念
- 进程号: PID (process id)计算机系统识别进程的唯一标识
- 父进程号:PPID
- 无论是PID还是PPID都是一个大于等于0的数字,而且每个进程的PID不可能相同
- linux系统想要查看能够创建多少个进程:cat/proc/sys/kernel/pid max
- 在linux系统下,在根目录下的proc目录下,以数字命名的目录,全部都是一个进程
查看当前系统可以创建PID的最大值:
查看当前进程:以数字为开头的都是正在执行的进程
思维导图
练习
1. 完成ls -la功能
int main(int argc, char const *argv[])
{
DIR* dp;
struct stat sb;//获取文件详情
struct tm* file_time;
int i = 0;
int z = 0;
int buff=0;
int buff1=0;
char power[11]={0};//权限
char file_name[50]={'.','/'};//文件名
if((dp=opendir("./"))==NULL)
{
perror("opendir: ");
return -1;
}
struct dirent* tp;
while((tp = readdir(dp)) != NULL)
{//循环查看文件夹下的文件
buff1=0x100;
z=0;
strcpy(file_name+2,tp->d_name);
/*获取文件属性*/
stat(file_name, &sb);
file_time = localtime(&sb.st_ctime);//计算文件时间
switch(sb.st_mode&__S_IFMT)
{
case __S_IFSOCK : power[0] = 's'; break;//套接字文件
case __S_IFLNK : power[0] = 'l'; break;//软连接文件
case __S_IFREG : power[0] = '-'; break;//普通文件
case __S_IFBLK : power[0] = 'b'; break;//块设备文件
case __S_IFDIR : power[0] = 'd'; break;//目录文件
case __S_IFCHR : power[0] = 'c'; break;//字符设备文件
case __S_IFIFO : power[0] = 'p'; break;//管道文件
default : break;
}
buff=sb.st_mode&0777;
for(i=1;i<10;i++)
{
z++;
if(z>3) z=1;
// printf("%#x\r\n",buff1);
switch(z)
{
case 1 : (buff&buff1)?(power[i] = 'r'):(power[i] = '-'); break;
case 2 : (buff&buff1)?(power[i] = 'w'):(power[i] = '-'); break;
case 3 : (buff&buff1)?(power[i] = 'x'):(power[i] = '-'); break;
}
buff1=buff1>>1;
}
printf("%s ",power);//链接号
printf("%3ld ",sb.st_nlink);//链接号
printf("%5d ",sb.st_uid);//所属用户
printf("%5d ",sb.st_gid);//所属组用户
printf("%7ld ",sb.st_size);//文件大小
printf("%.2dmon ",file_time->tm_mon+1);//文件最后修改日期(月)
printf("%.2dday ",file_time->tm_mday);//文件最后修改日期(日)
printf("%.2d:",file_time->tm_hour);//文件最后修改日期(时)
printf("%.2d ",file_time->tm_sec);//文件最后修改日期(时)
printf("%s",file_name+2);//文件名
printf("\r\n");//换行
}
return 0;
}
运行结果>>
drwxrwxr-x 6 1000 1000 4096 05mon 29day 08:56 ..
-rw-rw-r-- 1 1000 1000 427 05mon 29day 13:51 public.h
-rwxrwxr-x 1 1000 1000 12848 05mon 29day 20:22 main.out
drwxrwxr-x 2 1000 1000 4096 05mon 29day 08:56 .vscode
-rw-rw-r-- 1 1000 1000 0 05mon 29day 09:17 02file.txt
-rw-rw-r-- 1 1000 1000 19 05mon 29day 08:56 public.c
-rw-rw-r-- 1 1000 1000 2362 05mon 29day 20:19 main.c
drwxrwxr-x 3 1000 1000 4096 05mon 29day 20:22 .
-rw-rw-r-- 1 1000 1000 155 05mon 29day 09:23 01file.txt
-rw------- 1 1000 1000 380928 05mon 29day 08:56 core
终端结果: