0


操作系统之基础IO

基础IO

一、C语言文件操作

1、接口

FILE *fopen(constchar* filename,constchar* mode );intfclose( FILE * stream );size_tfwrite(constvoid* ptr,size_t size,size_t count, FILE * stream );size_tfread(void* ptr,size_t size,size_t count, FILE * stream );

2、默认打开的流

  • stdin:标准输入流,文件描述符默认为0,对应的物理设备一般是键盘。
  • stdout:标准输出流,文件描述符默认为1,对应的物理设备一般是显示器。
  • stderr:标准错误流,文件描述符默认为2,对应的物理设备一般是显示器。

二、Linux系统接口

1、open

(1)函数

在这里插入图片描述

(2)参数

  • pathname:要打开或创建的目标文件。
  • flags:打开文件时,用或运算传入多个参数选项。
  • mode:当目标文件不存在且需要open创建时,该参数表示创建文件的默认权限。
  • 返回值:打开或创建成功时,返回新打开或创建的文件的文件描述符;打开或创建失败时,返回-1。

2、close

(1)函数

在这里插入图片描述

(2)参数

  • fd:文件描述符。
  • 返回值:关闭成功,返回0;关闭失败,返回-1并正确地设置errno。

3、write和read

(1)函数

在这里插入图片描述
在这里插入图片描述

三、文件描述符fd

1、概念

  • 文件描述符是从0开始的小整数,当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件,即file结构体,表示一个已经打开的文件对象。
  • 进程执行open系统调用时,必须让进程和文件关联起来。每个进程都有一个指针files,指向一张表files_struct,该表最重要的部分就是包涵一个指针数组fd_array,数组中的每个元素都是一个指向打开了的文件的指针。所以,本质上文件描述符就是该数组的下标。即只要有文件描述符就可以找到对应的文件。
  • 文件描述符的分配规则为在files_struct对象的数组当中,找到当前没有被使用且为最小的一个下标,作为新的文件描述符进行分配。

2、图示

在这里插入图片描述

3、默认打开的文件描述符

  • 标准输入,文件描述符为0,对应的物理设备一般是键盘。
  • 标准输出,文件描述符为1,对应的物理设备一般是显示器。
  • 标准错误,文件描述符为2,对应的物理设备一般是显示器。

4、重定向

(1)概念

  • 以标准输出为例,输出重定向为当关闭文件描述符1时,再打开一个文件。此时,本来应该输出到标准输出(显示器)上的内容,输出到了该文件当中。
  • 其他重定向类似。

(2)代码

intmain(){close(1);int fd =open("log.txt", O_WRONLY | O_CREAT | O_TRUNC,0666);if(fd <0){perror("open");return1;}printf("snowdragon writed\n");printf("%d\n", fd);printf("%d\n", fd);printf("%d\n", fd);fflush(stdout);close(fd);return0;}

(3)运行结果

在这里插入图片描述

四、dup2系统调用

1、函数

在这里插入图片描述

2、作用

  • 使newfd成为oldfd的副本,如果有必要的话,会先关闭newfd。
  • 如果oldfd不是有效的文件描述符,则调用失败,并且newfd不会关闭。
  • 如果oldfd是一个有效的文件描述符,并且newfd的值与oldfd的值相同,则dup2不执行任何操作,并返回newfd。

3、代码

intmain(){int fd =open("log.txt", O_WRONLY | O_CREAT | O_TRUNC,0666);fprintf(stdout,"stdout writed\n");dup2(fd,1);fprintf(stdout,"fprintf writed\n");char s[]="fwrite writed\n";fwrite(s,strlen(s),1,stdout);close(fd);fprintf(stdout,"code end\n");return0;}

4、运行结果

在这里插入图片描述

五、磁盘

1、图片

在这里插入图片描述
在这里插入图片描述

2、作用

  • 磁盘是一个外设,也是计算机中唯一的一个机械设备。
  • 磁盘的盘面上会存储数据,但因为计算机只认识二进制,所以向磁盘盘面写入数据,本质就是通过磁头改变磁盘盘面上的特定位置的正负极。
  • 磁盘的基本单位是扇区(512byte),但是操作系统(文件系统)和磁盘进行IO的基本单位是4KB(8*512byte),所以一个块的大小为4KB。

3、抽象结构

在这里插入图片描述

4、各区的概念

  • Super Block:存储文件系统的属性信息。
  • Group Descriptor Table:块组描述符,保存该块组的属性,例如块组的大小和使用情况,inode与block的数量与使用情况。
  • Block Bitmap:每位比特位和特定的block具有一一对应的关系,当比特位为1时,代表该block被占用,否则表示可使用。
  • inode Bitmap:每位比特位和特定的inode具有一一对应的关系,当比特位为1时,代表该inode被占用,否则表示可使用。
  • inode:一个大小为128字节的空间,保存的是对应文件的属性。
  • inode Table:保存所有文件inode空间的集合,其中inode的数量是固定的。在块组内,需要标识唯一性,即每一个inode块都要有一个inode编号。一般而言,文件、inode和inode编号都是一一对应的。
  • Data blocks:多个block(4KB)的集合,其中data block的数量是固定的,且每个Data block保存的都是特定文件的内容。一个文件可以有多个data block,并且,不是所有的data block只能存文件数据,一些data block可以存储其他块的块编号。

六、软硬链接

1、inode与文件名的关系

  • 当查找在磁盘(不在内存)中的文件时,用户使用文件名查找,实际上操作系统是通过inode编号到磁盘的分区中去查找,当查找到指定的inode后再查找该inode的属性与内容。
  • 在Linux中的inode属性里面,不存在文件名。
  • 文件所在的目录也是一个文件,而文件名与inode编号的映射关系则存储在该目录的Data blocks中。

2、硬链接

  • 在指定的目录下,建立文件名和指定inode的映射关系,增加该文件(映射关系)的引用计数。
  • 不会产生新的inode,创建的硬链接都是同一个inode,即创建的硬链接都不是独立的文件。

3、软链接

  • 通过新的inode引用另外一个文件,而文件的引用计数不会发生变化。创建的软链接具有自己的inode,即它是一个独立的文件。

4、ln命令

在这里插入图片描述
在这里插入图片描述

5、示例

在这里插入图片描述

七、静态库与动态库

1、概念

  • 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。
  • 动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序可以共享使用库的代码。
  • 静态库与动态库的库名需要加前缀lib。
  • 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码。
  • 动态链接(dynamic linking):在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中。
  • 动态库可以让多个程序共享,所以动态链接形成的可执行文件较静态链接的小。操作系统采用虚拟内存机制允许物理内存中的一份动态库被用到使用该库的所有进程中,进而节省了内存和磁盘空间。

2、制作库

(1)ar命令

在这里插入图片描述

  • ar是gnu归档工具。
  • r:插入文件成员…(member…)进入存档(替换)。如果之前存在的任何成员的名称与要添加的成员的名称匹配,则将其删除。如果member…不存在,则ar显示错误信息,然后离开,与该名称匹配的存档的任何现有成员不受干扰。
  • c:创建存档。 当请求更新并且指定的存档不存在时,则始终创建指定的存档。 但是使用此修饰符时,除非事先指定希望创建它,否则会发出警告。

(2)具备的文件

在这里插入图片描述

(3)代码

  • makefile代码
.PHONY:all                                                                                                    
   all:libsnow.a libsnow.so
libsnow.so:mymath_d.o myprint_d.o
   gcc -shared mymath_d.o myprint_d.o -o libsnow.so
mymath_d.o:mymath.c
   gcc -c -fPIC mymath.c -o mymath_d.o
myprint_d.o:myprint.c
   gcc -c -fPIC myprint.c -o myprint_d.o

libsnow.a:mymath.o myprint.o
   ar -rc libsnow.a  mymath.o myprint.o
mymath.o:mymath.c
   gcc -c mymath.c -o mymath.o
myprint.o:myprint.c
   gcc -c myprint.c -o myprint.o
 
snow:mymath.h myprint.h libsnow.a libsnow.so
   mkdir -p snow/include
   mkdir -p snow/lib
   cp-rf *.h snow/include
   cp-rf *.a snow/lib
   cp-rf *.so snow/lib
 
.PHONY:clean
clean:
   rm-rf *.o *.a *.so snow
  • shared:表示生成共享库格式。
  • fPIC:产生位置无关码。

3、使用库

(1)拷贝到指定目录下

  • .h后缀的头文件添加到头文件的默认搜索路径/usr/include/目录下。
  • .a或者.so后缀的库文件添加到库文件的默认搜索路径/lib64目录下。

(2)指定路径

  • 执行gcc 使用库的源文件 -I 头文件搜索路径 -L 库文件搜索路径 -l库名(去掉前缀lib和后缀.a或.so)。在这里插入图片描述
  • 使用动态库时,需要设置环境变量才能链接动态库。
  • 注意,设置的路径是使用该动态库的路径,而不是该动态库所在的路径。在这里插入图片描述

本文到这里就结束了,如有错误或者不清楚的地方欢迎评论或者私信
创作不易,如果觉得博主写得不错,请点赞、收藏加关注支持一下💕💕💕


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

“操作系统之基础IO”的评论:

还没有评论