Linux 学习记录23(IO篇+静/动态库+多进程理论)

本文详细介绍了Linux中的文件状态获取,包括stat函数的使用来获取文件属性,如文件类型和权限。接着讨论了对目录的操作,如打开、读取和关闭目录。然后讲解了Linux系统中的静态库和动态库的创建及使用。最后,文章深入探讨了多进程理论,包括进程的概念、内存管理和进程的组成部分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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:要获取属性的文件路径
参数2struct 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参数能够获得文件的类型与权限

  1. st mode&S_IFMT ------------>能够得到文件类型

在这里插入图片描述
S_IFSOCK 套接字文件
S_IFLNK软连接文件
S_IFREG 普通文件
S_IFBLK 块设备文件
S_IFDIR 目录文件
S_IFCHR 字符设备文件
S_IFIFO 管道文件

  1. 使用函数 ------------>能够得到文件类型

在这里插入图片描述

  1. 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系统中的库

  1. Linux中的库本质上是一个二进制文件,由.c文件(不包含main)编译而来其他程序可以使用该库调用相关的函数
  2. 包含静态库动态库两种
  3. 不同操作系统对库的格式有所不同
  1. windows: xxx.lib=静态库,xxx.dll=动态库两种
  2. Linux: libxxx.a = 静态库,libxxx.so = 动态库两种
  1. 由于库是二进制文件,.c文件编译后生成库后,函数的实现过程是看不到的,所以使用库比较安全
使用ldd命令可以查看文件所依赖的头文件

在这里插入图片描述

例如 printf函数需要头文件------>#include <stdio.h>
但是该头文件只有函数的声明,
函数的实现在lib.so库中(Linux系统中的动态库)

1. 静态库

将xxx.c文件编译生成的一个库名为.a的二进制文件,当需要使用该库中的某个函数时,直接调用该函数即可,前提是编译时链接了该库

  1. 动态态:在使用gcc编译时,会将你的我加你和库文件一起生成一个可执行文件,在最终可执行程序在包含了静态库,但是程序体积一般比较大,但是在执行程序时,无需去寻找该库的位置,效率较高

(1. 静态库的创建

  1. 准备好.c源文件
    在这里插入图片描述
  2. 准备好对于的.h头文件
    在这里插入图片描述
  3. 准备测试文件
    在这里插入图片描述
  4. 编译生成
    在这里插入图片描述
  5. 编译测试
    在这里插入图片描述

命令:gcc -c add.c -o add.o

  1. 只生成不链接

命令:ar -cr libadd.a add.o

  1. ar->说明这是静态库的命令
  2. -c->创建
  3. -r->允许使用该函数
  4. 如果使用多个.o文件生成库 ar -crs 库名.a add1.o add2.o…

命令:gcc main.c -L ./ -ladd -I ./

  1. -L : 指定库的路径
  2. -l :所需库的名字
  3. -I :指定头文件的路径

2. 动态库

静态库只,将xxx.c文件编译生成的一个库名为.a的二进制文件,当需要使用该库中的某个函数时,直接调用该函数即可,前提是编译时链接了该库

  1. 静态:在使用gcc编译时,会将你的我加你和库文件一起生成一个可执行文件,但是程序体积较小,但是在执行程序时,需去寻找该库的位置,效率较低,但是可以由多个文件共享一个文件,动态库又称共享库

(1. 动态库的创建

  1. 准备好.c源文件
    在这里插入图片描述
  2. 准备好对于的.h头文件
    在这里插入图片描述
  3. 准备测试文件
    在这里插入图片描述
  4. 编译生成
    在这里插入图片描述
    在这里插入图片描述
  5. 测试
    在这里插入图片描述
  6. 解决上述错误
  1. 在命令行指定库的路径:export LD_LIBRARY_PATH=库的路径(仅在当前终端有效)
    在这里插入图片描述
  2. 将上述的库放入系统库中(/lib或/usr/lib)
    在这里插入图片描述
  3. 更改系统在库的配置文件
    在这里插入图片描述
    在这里插入图片描述

命令: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. 进程的概念

进程:程序的一次执行过程

  1. 进程就是正在执行的程序
  2. 进程是一个动态的过程,是有生命周期的,随着经常的创建而出现,随着经常的消亡而销毁
  3. 进程是分配资源的最小单位,每个进程都会拥有自己的0-3G的用户空间,但是共享3–4G的内核空间
  4. 这0–3G的用户空间又被分为三个部分: 栈区、堆区、静态区
  5. 进程在内核空间由一个task struct结构体表示

2. 进程的内存管理 (重点!!!)

  1. 每个进程都会分配4G的空间(虚拟内存)
  2. 每个进程都都拥有独立的0-3G的用户空间,3-4G的内核空间是共享的

3. 程序和进程的区别

进程:进程是动态的,有生命周期,是程序的一次执行过程,每个进程拥有0--3G的用户空间
并且共享3--4G的内核空间

程序:程序是静态的,没有生命周期可言,它是在磁盘上的一个二进制文件

4. 进程的组成

  1. 进程由三部分组成:进程控制段(PCB)、数据段、程序段
  2. 进程控制段:是内核空间分配的一个task strut的结构体,包含了一个进程的所有信息: PID、进程的状态、相关寄存器
  3. 数据段:在进程执行过程中,中间数据存放的位置:.data bss
  4. 程序段:存放程序允许的代码: text

5. 进程的种类

  1. 进程一共有三种:交互进程、批处理进程、守护进行
  2. 交互进程:他是由shel脚本控制,可以直接跟用户进行交互的进程,例如文本编辑器
  3. 批处理进程:维护了一个队列,被放到该队列中的进程会统一被处理,例如终端执行./a.out
  4. 守护进程:他是脱离终端而存在,例如服务进程

6. 进程的PID概念

  1. 进程号: PID (process id)计算机系统识别进程的唯一标识
  2. 父进程号:PPID
  3. 无论是PID还是PPID都是一个大于等于0的数字,而且每个进程的PID不可能相同
  4. linux系统想要查看能够创建多少个进程:cat/proc/sys/kernel/pid max
  5. 在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

终端结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值