当前课程知识点:基于Linux的C++ > 第十二讲 Linux系统编程基础 > 12.6 输入输出(一) > LinuxCPP1206
接下来第二节
是 Linux 操作系统的输入输出
在这一节里我们要讲四个主题
一个是标准输入输出流
第二个是文件描述符
第三个是 I/O 函数
第四个是临时文件
我们首先来看标准输入输出流
标准输入流就是 stdin
在 C++ 下面就是 cin
标准输出流就是 stdout
在 C++ 下面就是 cout
在 Linux 操作系统中
标准输出流是有缓冲的
在缓冲区满 程序正常退出
流被刷新 被关闭
只有这种时候它才会输出
对于标准错误流 stderr
在 C++ 里边就是 cerr
它是无缓冲的
数据是直接输出的
所以用这两段代码运行一下
你就会发现
它这个数据的输出是不一样的
不过有的操作系统的实现
可能在这一点上不一样
就是它有的时候
它的数据可能都是无缓冲
就直接全输出了
理论上标准输出流是有缓冲的
而标准错误流是无缓冲的
在 Linux 操作系统的底层
它使用文件描述符来代表资源
一开始这个文件描述符
它表达的是什么东西呢
表达的就是文件
在 Linux 操作系统中
它使用文件描述符
来表达底层的资源概念
文件描述符
它的最主要目的
就是在我们的程序中代表文件
操作系统的内核为每个进程
维护一个文件打开的记录表
而我们的文件描述符就是
它那个文件在这个文件记录表中的索引值
它那个文件在这个文件记录表中的索引值
用这个文件描述符代表着那个文件
操作系统就用文件描述符
来描述那个文件资源
文件描述符在实现的时候是一个非负的整数
文件描述符在实现的时候是一个非负的整数
它的范围从 0 到 OPEN_MAX 之间
因为不同的操作系统的实现是不一样的
所以不同的操作系统
它的那个 OPEN_MAX 这个值是不一样大的
所以不同的操作系统所能够同时打开的
资源的数目是不一样的
事实上在 Linux 操作系统里边
所有的东西都是文件
其实都可以使用文件描述符来描述它
不过有一点是需要特别注意的
在非 Unix/Linux 操作系统里边
它可能没有使用文件描述符这个概念
所以当你想访问文件的时候
想访问外部资源的时候
要编写跨平台的程序
那么就应该慎用文件描述符
换了一个操作系统
文件描述符它可能就没法工作
没这东西 就不能用
这个地方需要特别注意的
所以真实我们写程序的时候
尽量不用文件描述符
用的更多的
其实应该是 C/C++ 标准库里边的函数或文件流类来处理文件
其实应该是 C/C++ 标准库里边的函数或文件流类来处理文件
那个方式跨平台的兼容性更好
在 Linux 操作系统中预定义的
标准输入输出流的文件描述符有三个:
标准输入流、标准输出流、标准错误流
它们对应的文件描述符是 STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO
它们对应的文件描述符是 STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO
它们对应的数值分别为 0、1、2
这是最小的三个文件描述符
很多 Linux 程序都可以创建文件描述符
因为我们刚才不是说了嘛
在 Linux 操作系统里边
凡物皆文件
所以操作系统
它是以一个统一的方式维护和管理我们的系统资源的
它是以一个统一的方式维护和管理我们的系统资源的
打开一个系统资源
它就会为它创建一个文件描述符
所以很多很多 Linux 的函数
它的系统调用
都会打开一个文件描述符
通过打开文件或者设备这样一种方式
来创建文件描述符
很多这样的函数都会做这个事情
它都会返回一个文件描绘符
一旦你打开一个文件或打开一个设备
它就会创建一个文件描述符给你
然后你就可以用这个文件描述符
来操纵那个文件或设备了
就是这个意思
所以文件描述符在 Linux 底层设计的时候
是非常非常重要的
但事实上一旦要跨平台
我们其实就不应该频繁用到
所以这个地方同学们要特别注意
Linux 操作系统提供一系列基本 I/O 函数和高级 I/O 函数
Linux 操作系统提供一系列基本 I/O 函数和高级 I/O 函数
比如讲打开关闭函数 open()、close()
比如讲读写函数 read() 和 write()
比如讲 readv() 和 writev()
这是分散读、集中写函数
比如讲文件发送函数 sendfile()
比如讲数据移动函数 splice() 和 tee()
比如讲文件控制函数 fcntl()
所有这些函数你在进行 Linux 系统编程的时候都可以使用
所有这些函数你在进行 Linux 系统编程的时候都可以使用
你比如讲 打开文件函数 open()
它的基本格式需要带一个 filename
后边是 oflag
后面跟着它的可选的参数
打开那个对应的文件
按照特定的标志来打开
它有文件打开标志的
oflag 代表的就是文件打开标志
关闭一个文件
你不用了 就 close() 关闭它
传一个文件描述符就 OK 了
read() 和 write() 就是进行文件的读写
第一个参数都是它对应的文件描述符
读写的数据从文件中来和到文件中去
这个读取的数据放哪呢 放到 buf 里
写呢 就写到文件中去
那么写的数据从哪来呢
也是从 buf 里边来
写多少个字符 读多少个字符呢
那就第三个参数 count 来限定
这是读写函数
要想提升效率
就可以用分散的读函数 readv() 和集中写函数 writev()
就可以用分散的读函数 readv() 和集中写函数 writev()
这两个函数呢
它不仅带着文件描述符
它还带着什么呢
它带着这个数据的读写的来源或者目的
你如果是分散读的话
就从文件描述符 fd 所代表的
那个文件里边把这个数据读进来
读进来以后分散地写到
iov 所代表的那个数据的数组里
iov 是 const struct 的这样一个数组
它其实是一个数组
你看它是一个指针
这个数组中的每一个成员都是 struct iovec
输入输出向量 它会带两个字段
一个是 iov_base 一个是 iov_len
iov_base 就是指向那个内存的基地址
读取的数据要写到哪个内存里
那个内存的基地址 然后要写多长
就是那个存储空间有多大
你就写进去 这是一块
iov 是一个向量
它实际上是一个数组
那么在这里
这个数组里包含很多个元素
也就是写的块是有好多个这样的块
也就是写的块是有好多个这样的块
你都可以分散写进去
所以这就要分散的读
我们从文件中读数据
然后分散写出去 写到内存里
就叫分散读取 然后集中写呢
就是把所有的分散在 iov 里边的这些数据
一块、一块、一块地
然后集中地写到我们的文件里
这叫 writev()
这两个函数 分散读取 集中写 readv()/writev()
这两个函数 分散读 集中写
它有什么好处呢
就是当你按照这样一个模式进行操作的时候
就是当你按照这样一个模式进行操作的时候
它这个数据处理的模式
就比简单的单一读取效率要高 要快
因为从文件中一读就读好多块
一写呢就集中地把好多块数据就全写出去了
一写呢 就集中地把好多块数据就全写出去了
这个效率显然要比直接读取的那个
和写入的那个函数效率要高
-1.1 提纲
-1.2 程序设计的基本概念
-1.3 简单C/C++程序介绍
-1.4 程序设计的基本流程
-1.5 基本语法元素
-1.6 程序设计风格
-1.7 编程实践
-第一讲 C/C++基本语法元素--编程实践提交入口
-2.1 提纲
-2.2 结构化程序设计基础
-2.3 布尔数据
-2.4 分支结构
-2.5 break语句
-2.6 循环结构
-2.7 编程实践
-第二讲 程序控制结构--编程实践提交入口
-3.1 提纲
-3.2 函数声明、调用与定义
-3.3 函数调用栈框架
-3.4 编程实践
-第三讲 函数--编程实践提交入口
-4.1 提纲
-4.2 算法概念与特征
-4.3 算法描述
-4.4 算法设计与实现
-4.5 递归算法(一)
-4.6 递归算法(二)
-4.7 容错与计算复杂度
-4.8 编程实践
-第四讲 算法--编程实践提交入口
-5.1 提纲
-5.2 库与接口
-5.3 随机数库(一)
-5.4 随机数库(二)
-5.5 作用域与生存期
-5.6 典型软件开发流程(一)
-5.7 典型软件开发流程(二)
-5.8 编程实践
-第五讲 程序组织与开发方法--编程实践提交入口
-6.1 提纲
-6.2 字符
-6.3 数组(一)
-6.4 数组(二)
-6.5 结构体
-6.6 编程实践
-第六讲 复合数据类型--编程实践提交入口
-7.1 提纲
-7.2 指针基本概念
-7.3 指针与函数
-7.4 指针与复合数据类型(一)
-7.5 指针与复合数据类型(二)
-7.6 字符串
-7.7 动态存储管理(一)
-7.8 动态存储管理(二)
-7.9 引用
-7.10 编程实践
-第七讲 指针与引用--编程实践提交入口
-8.1 提纲
-8.2 数据抽象(一)
-8.3 数据抽象(二)
-8.4 链表(一)
-8.5 链表(二)
-8.6 链表(三)
-8.7 链表(四)
-8.8 函数指针(一)
-8.9 函数指针(二)
-8.10 抽象链表(一)
-8.11 抽象链表(二)
-8.12 编程实践
-第八讲 链表与程序抽象--编程实践提交入口
-9.1 提纲
-9.2 程序抽象与面向对象
-9.3 类类型
-9.4 对象(一)
-9.5 对象(二)
-9.6 类与对象的成员(一)
-9.7 类与对象的成员(二)
-9.8 类与对象的成员(三)
-9.9 继承(一)
-9.10 继承(二)
-9.11 继承(三)
-9.12 多态(一)
-9.13 多态(二)
-9.14 编程实践
-第九讲 类与对象--编程实践提交入口
-10.1 提纲
-10.2 四则运算符重载(一)
-10.3 四则运算符重载(二)
-10.4 关系与下标操作符重载
-10.5 赋值操作符重载(一)
-10.6 赋值操作符重载(二)
-10.7 赋值操作符重载(三)
-10.8 赋值操作符重载(四)
-10.9 赋值操作符重载(五)
-10.10 流操作符重载(一)
-10.11 流操作符重载(二)
-10.12 流操作符重载(三)
-10.13 操作符重载总结
-10.14 编程实践
-第十讲 操作符重载--编程实践提交入口
-11.1 提纲
-11.2 泛型编程概览
-11.3 异常处理机制(一)
-11.4 异常处理机制(二)
-11.5 运行期型式信息(一)
-11.6 运行期型式信息(二)
-11.7 模板与型式参数化
-11.8 题外话:术语翻译
-11.9 泛型编程实践(一)
-11.10 泛型编程实践(二)
-11.11 泛型编程实践(三)
-11.12 泛型编程实践(四)
-11.13 泛型编程实践(五)
-11.14 泛型编程实践(六)
-11.15 泛型编程实践(七)
-11.16 泛型编程实践(八)
-11.17 泛型编程实践(九)
-11.18 泛型编程实践(十)
-11.19 编程实践
-第十一讲 泛型编程--编程实践提交入口
-12.1 提纲
-12.2 程序执行环境(一)
-12.3 程序执行环境(二)
-12.4 程序执行环境(三)
-12.5 程序执行环境(四)
-12.6 输入输出(一)
-12.7 输入输出(二)
-12.8 文件系统
-12.9 设备
-12.10 库(一)
-12.11 库(二)
-12.12 makefile文件(一)
-12.13 makefile文件(二)
-12.14 makefile文件(三)
-12.15 编程实践
-第十二讲 Linux系统编程基础--编程实践提交入口
-13.01 提纲
-13.02 进程基本概念
-13.03 信号
-13.04 进程管理(一)
-13.05 进程管理(二)
-13.06 进程管理(三)
-13.07 进程间通信(一)
-13.08 进程间通信(二)
-13.09 进程间通信(三)
-13.10 进程间通信(四)
-13.11 进程池
-13.12 编程实践
-第十三讲 进程编程--编程实践提交入口
-14.1 提纲
-14.2 线程基本概念
-14.3 线程管理(一)
-14.4 线程管理(二)
-14.5 线程管理(三)
-14.6 线程管理(四)
-14.7 线程同步机制(一)
-14.8 线程同步机制(二)
-14.9 C++11线程库(一)
-14.10 C++11线程库(二)
-14.11 C++11线程库(三)
-14.12 C++11线程库(四)
-14.13 C++11线程库(五)
-14.14 编程实践
-第十四讲 线程编程--编程实践提交入口
-15.1 提纲
-15.2 Internet网络协议
-15.3 套接字(一)
-15.4 套接字(二)
-15.5 编程实践
-第十五讲 网络编程--编程实践提交入口