【Linux】基础IO

简介: 【Linux】基础IO

基础IO

1. 系统文件I/O

操作文件,除了C接口外,我们还可以采用系统接口来进行文件访问,我们来看看如下代码:

读文件

1.1 接口介绍

open man open

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char* pathname, int flags);
int open(const char* pathname, int flag, mode_t mode);
pathname: 要打开或者创建的目标文件
flags:打开文件时,可以传入多个参数选项,用下面的一个或者多个进行“或”运算,构成flags
参数:
    O_RDONLY:只读打开
    O_WRONLY:只写打开
    O_RDWR:读,写打开
        这三个常量必须指定,并且只能指定一个
    O_CREAT:若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
    O_APPEND:追加写
返回值:
    成功:新打开的文件描述符
    失败:-1

open函数具体使用那个,和具体的应用场景有关,如果目标文件不存在,需open创建,第三个参数表示创建文件的默认权限。

1.2 open函数返回值

认识一下两个概念:系统调用和库函数

  • fopenfclosefreadfwrite都是C语言标准库中的函数,我们称之为库函数
  • openclosereadwritelseek 都属于系统提供的接口,称为系统调用接口

之前的博客中用到的一张图:

系统调用接口和库函数的关系一目了然


1.3 文件描述符

我们知道了文件描述符就是一个小小的整数

在计算机操作系统中,文件描述符是用于访问文件和I/O设备的一个抽象概念。它是一个非负整数,用来标识一个已经打开的文件或I/O设备。在Unix、Linux和其他类Unix系统中,文件描述符是一种非常常见的概念。


文件描述符通常被用于在程序中访问打开的文件或设备,如磁盘文件、标准输入、标准输出等。它们是一种轻量级的机制,能够提供高效、灵活的I/O操作,因为它们可以被用来表示任何类型的I/O流,包括文件、管道、套接字等。


文件描述符通常是通过调用系统调用(如open、close、read、write等)返回的,操作系统会维护一个表格来跟踪打开的文件和设备以及相应的文件描述符。在使用文件描述符时,程序需要保证文件描述符的唯一性,因为文件描述符是在系统范围内唯一的。


一般来说,标准输入、标准输出和标准错误输出的文件描述符分别是0、1、2。其他文件描述符的值通常是由操作系统分配的,通常是一个递增的整数。例如,打开一个文件会返回一个新的、当前未使用的文件描述符。关闭文件时,该文件描述符会被释放,并可以被其他打开的文件或设备使用。

1.4 0 & 1 & 2

  • Linux默认情况下会有3个缺省打开的文件描述符,分别是标准输入0,标准输出1,标准错误2
  • 0,1,2对应的物理设备一般是:键盘,显示器,显示器

所以输入和输出还可以采用如下方式:

现在我们知道,文件描述符就是从0开始的整数。当我们打开文件的时候,操作系统要创建相应的数据结构来描述目标文件,于是就有了file结构体。表示已经打开的文件对象。而执行open系统调用,所以必须要让进程和文件关联起来。每个进程都有一个*files指针,指向一张表files_struct,这个表最重要的部分就是包含了一个指针数组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是这个数组的下标。所以,只要拿着文件描述符就可以找到对应的文件

1.5 文件描述符的分配规则

我们可以查看如下代码:

输出查看我们发现是:3

关闭0或者2重新查看:

我们可以发现这个规律:文件描述符的分配规则:在files_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符

1.6 重定向

如果我们关闭1会发生怎么的事情呢?我们看如下代码:

此时我们发现本该在显示器上显示的内容,输出到了文件当中。这种现象叫做重定向

2. 使用dup2系统调用

函数原型是这样:

#include <unistd.h>
int dup2(int oldfd, int newfd);

printf是C库当中的一个IO函数,一般往stdout中输出,但是stdout访问底层文件的时候还是找的是fd : 1,但是fd1已经变成了myfile的地址,不在是显示器文件的地址,所以输出的任何消息都是往文件中写入,进而完成输出重定向。

3. FILE

  • 因为IO相关的函数与系统调用接口对应,并且库函数封装系统调用,所以本质上访问文件都是通过fd访问的
  • C库的FILE内部,必定封装了fd

以上的代码运行结果是:

但是我们如果对进程实现输出重定向会怎么样?.test > myfile,我们发现结果是这样:

我们发现printffwrite都输出了两次,但是write只输出了一次(系统调用)这是为什么?

  • 一般C库函数写入文件是全缓冲,但是写入显示器是行缓冲
  • printffwrite自带缓冲区,当发生重定向到普通文件的时候,数据的缓冲方式变成了全缓冲
  • 而我们放在缓冲区的数据就不会立即刷新,甚至fork之后
  • 但是进程退出之后,会统一刷新,写入到文件当中
  • fork的时候父子进程数据会发生写时拷贝,所以当父进程准备刷新的时候,子进程也有了同样的数据,随机产生两份数据
  • write没有所谓的缓冲

所以我们可以发现:printffwrite库函数自带缓冲区,而write系统调用没有带缓冲区,另外这里的缓冲区都是用户级缓冲区

相关文章
|
1月前
|
网络协议 安全 Linux
Linux C/C++之IO多路复用(select)
这篇文章主要介绍了TCP的三次握手和四次挥手过程,TCP与UDP的区别,以及如何使用select函数实现IO多路复用,包括服务器监听多个客户端连接和简单聊天室场景的应用示例。
92 0
|
1月前
|
存储 Linux C语言
Linux C/C++之IO多路复用(aio)
这篇文章介绍了Linux中IO多路复用技术epoll和异步IO技术aio的区别、执行过程、编程模型以及具体的编程实现方式。
86 1
Linux C/C++之IO多路复用(aio)
|
3月前
|
缓存 安全 Linux
Linux 五种IO模型
Linux 五种IO模型
|
1月前
|
Linux C++
Linux C/C++之IO多路复用(poll,epoll)
这篇文章详细介绍了Linux下C/C++编程中IO多路复用的两种机制:poll和epoll,包括它们的比较、编程模型、函数原型以及如何使用这些机制实现服务器端和客户端之间的多个连接。
25 0
Linux C/C++之IO多路复用(poll,epoll)
|
3月前
|
小程序 Linux 开发者
Linux之缓冲区与C库IO函数简单模拟
通过上述编程实例,可以对Linux系统中缓冲区和C库IO函数如何提高文件读写效率有了一个基本的了解。开发者需要根据应用程序的具体需求来选择合适的IO策略。
34 0
|
3月前
|
存储 IDE Linux
Linux源码阅读笔记14-IO体系结构与访问设备
Linux源码阅读笔记14-IO体系结构与访问设备
|
4月前
|
Linux 数据处理 C语言
【Linux】基础IO----系统文件IO & 文件描述符fd & 重定向(下)
【Linux】基础IO----系统文件IO & 文件描述符fd & 重定向(下)
77 0
|
4月前
|
Linux 编译器 C语言
【Linux】基础IO----理解缓冲区
【Linux】基础IO----理解缓冲区
70 0
【Linux】基础IO----理解缓冲区
|
4月前
|
缓存 网络协议 算法
【Linux系统编程】深入剖析:四大IO模型机制与应用(阻塞、非阻塞、多路复用、信号驱动IO 全解读)
在Linux环境下,主要存在四种IO模型,它们分别是阻塞IO(Blocking IO)、非阻塞IO(Non-blocking IO)、IO多路复用(I/O Multiplexing)和异步IO(Asynchronous IO)。下面我将逐一介绍这些模型的定义:
219 2
|
5月前
|
Linux 编译器 C语言
【Linux】基础IO_4
【Linux】基础IO_4
29 3
下一篇
无影云桌面