0


【Linux课程学习】:文件第一弹---文件基础(文件描述符的底层设计)

🎁个人主页:我们的五年

**🔍系列专栏:Linux课程学习 **

🌷追光的人,终会万丈光芒

🎉欢迎大家点赞👍评论📝收藏⭐文章

Linux学习笔记:

https://blog.csdn.net/djdjiejsn/category_12669243.html

前言:

这篇主要谈论的是关于文件的基础,让我们在接下来能更好的理解文件描述符,系统调用的相关的文件函数,和语言层封装的f系列的函数。对于这篇文章,会从C语言文件接口,C语言默认打开的三个输入输出流,认识系统文件调用接口,这几个方面介绍文件,打好基础。


本节重点知识点:

1.fopen和fclose属于运行时操作。

2.深刻理解先描述,再组织。管理对象时,就要先进行描述。

3.理解一切皆文件,硬件设备对于进程来说也是文件。

4.文件描述符的底层设计--->进程与文件是怎么进行关联的。

一.预备知识

文件的分类****位置被打开的文件内存没有被打开的文件磁盘

在文件中,没有被打开的文件比被打开的文件多的多。下面我们研究的被打开的文件。研究被打开的文件,是在研究文件与进程的关系,但是进程会描述文件,所以我们研究的是文件与file_struct的关系

1.1文件=内容+属性:

对于我们创建的空文件,也是有大小的。虽然文件没有内容,但是文件有属性,在文件中要保存这些属性,就会有大小。

1.2在访问文件之前,必须先打开它:

在C语言中,我们很明显的感受到,在进行文件操作之前,必须打开文件(fopen)。然后进行一系列的操作,最后关闭文件(fclose)。

FILE* fd=fopen("log.txt","w");
fclose(fd);

1.2.1但是为什么要打开文件呢?

因为文件一开始在磁盘中保存着,要打开文件,也就是把文件加载到内存中,才能对文件进行操作。fopen是运行时操作,当被运行到fopen这一行代码,才被进程所打开。

所以文件被打开时,是进程在进行访问。

但是进程在内存中,CPU要想访问文件,因为冯诺依曼体系,CPU不能直接去磁盘进行访问,所以只能把文件加载到内存,才能被CPU访问。

1.3管理文件---先描述,在组织

凡是要进行管理的,就先要对管理的对象进行描述(struct),描述文件的属性。然后才能对文件进行管理。文件描述的一些属性,可以由文件的属性获得,还有其他很多属性要OS进行描述。


二.C语言文件操作函数

从C语言的角度看文件,和文件接口。有一个预备的知识。也为后面语言层面的封装与系统接口进行区分和比较。

2.1文件打开的方式:

文件打开方式功能效果w

文件不存在,新建文件。文件存在,清空文件。
w+读写文件不存在,新建文件。文件存在,清空文件。r读读取存在的文件,文件不存在,报错。r+读写读写存在的文件,文件不存在,报错。a追加在文件末尾追加,文件不存在,新建文件。a+读写在文件末尾读写,文件不存在,新建文件。
另外还可以增加b,比如wb,ab,rb。有b的,就是对二进制文件进行操作。其他的效果和上面类似,也是读(read),写(write),追加(append)。如果我们使用w方式,如果文件存在,会对文件进行清空(truncate)。

当我们输入重定向的时候,要以w方式打开文件,如果没有输入什么东西,文件就被我们清空了。

 > log.txt

2.2输出信息到显示器的方法:

int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);

fprintf的用法和printf差不多,只需要在前面指明文件对象,就能向指定的文件进行打印。

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

size_t fwrite(const void *ptr, size_t size, ize_t nmemb, FILE *stream);

#include <stdio.h>    
#include <string.h>    
    
int main()    
{    
    FILE* fd=fopen("log.txt","w");    
    if(fd==NULL)    
    {    
        printf("open error!\n");    
    }    
    fprintf(stdout,"hello fprintf!\n");    
    
    const char* message="hello fwrite!\n";    
    fwrite(message,strlen(message),1,stdout);       
    fclose(fd);    
} 


三.进程默认打开的三个标准流

在下面我们会讲解如何理解键盘,显示器这些硬件也是文件。即一切皆文件

stdin标准输入键盘stdout标准输出显示器stderror标准错误显示器


四.系统调用接口---系统文件I/O

我们使用的C语言文件操作函数,底层是封装了系统类的文件调用。比如C语言的w方式打开,可能是在封装open,并且使用O_WRONLY | O_CREAT | O_TRUNC。mode设置为0666。

4.1open系统调用

4.1.1函数原型:

头文件:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

函数原型:

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

4.1.2函数理解:

pathname:

和C语言的的fopen一样,也是文件的名称,是要打开或者创建的文件,名称。

flags:

是标记位,是int类型,表示要以什么方式进行打开,其本质是位图的思想。某个比特位上有1就表示一个功能。后面我们要使用多个功能时,是需要把代表不同功能的整数,进行按位或就可以达到目的。

flags分类有:
O_RDONLY只读方式打开O_WRONLY只写方式打开O_WDWR读写方式打开
上面的这三个参数,必须要有一个,并且只能有一个,要不就是只读,要不就是只写,要不就是读写。
O_CREAT如果文件不存在,创建文件。需要使用mode函数。O_APPEND以追加的方式进行写。O_TRUNC对文件进行清空。
返回值:

如果打开成功,就返回新打开的文件描述符。

如果失败就返回-1。

mode选项的函数,表示新创建文件的起始权限。文件的起始权限一般是0666,目录的起始权限一般是0777。所以我们在有O_CREAT时,应该加上对应的权限。但是最终的权限会&(~umask)。也可以设置文件的umask,最终可以让权限是0666。系统有umask,进程也有umask,最终使用的umaks是就近原则

int ft=open("log.txt",O_WRONLY|O_TRUNC);

五.文件描述符fd

5.1见一见其他文件的文件描述符fd:

文件描述符是整数。让我们看看打开其他文件时的文件描述符是多少?

#include <stdio.h>    
#include <string.h>    
#include <sys/types.h>    
#include <sys/stat.h>    
#include <fcntl.h>    
#include <unistd.h>        
    
int main()    
{    
    
    int fd1=open("log1.txt",O_WRONLY|O_TRUNC|O_CREAT);                                                                                                                                                             
    int fd2=open("log2.txt",O_WRONLY|O_TRUNC|O_CREAT);    
    printf("fd1:%d\n",fd1);    
    printf("fd2:%d\n",fd2);    

    close(fd1);    
    close(fd2);    
    return 0;
}

我们发现文件描述符fd不是从0开始的,而是从3开始的,为什么呢?

5.2stdin,stdout,stderror的文件描述符:

名称文件描述符硬件stdin0键盘stdout1显示器stderror2显示器
在打开我们的文件时,进程已经帮我们打开这个三个文件。这三个文件的文件描述符是0,1,2。所以我们打开其他文件的时候,就只能从3开始了。在后面的文件描述符的分配规则是占据最小空的元素。

5.3文件描述符的底层设计:

我们观察文件描述符是从0开始的,这很像数组。就可能存在一个表结构,让进程与文件管理起来。

5.3.1文件管理:

被打开的文件,会加载到内存中,加载之前就会对文件进行先描述,然后再进行组织。最后在内存中就会有很多的file_struct,他们之间的联系用某种数据结构进行关联起来。最后形成了一张file list的表。

5.3.2进程中的文件描述指针的数组:

在进程中,会存在一个文件描述指针数组的指针。这个指针指向是一个文件描述指针数组。这个数组从0开始。这个数组的第一个元素,也就是0号下标,指向的是stdin文件。

第二个元素,指向的是stdout文件。第三个元素就是指向就是stderror。

其他被打开的文件被串在file list中。如果被该进程打开,就会把这个文件的描述信息的指针放在文件描述符表中。

关闭文件本质就是在文件描述符表中删除某个文件的指针。

打开一个文件本质就是把文件指针放在文件描述符表中。

这样就可以让进程与文件关联起来。

5.3.3每个进程都会有文件描述符表:

每个进程中的文件描述符表中的元素都是指向文件的。应该文件可以被多个进程指向。


标签: 学习 linux 服务器

本文转载自: https://blog.csdn.net/djdjiejsn/article/details/144079895
版权归原作者 我们的五年 所有, 如有侵权,请联系我们删除。

“【Linux课程学习】:文件第一弹---文件基础(文件描述符的底层设计)”的评论:

还没有评论