标准I/O和系统调用概述
I/O就是输入和输出,输入输出是在开发中非常常用的操作,通过输入和输出,用户和程序能够进行交互。比如用户通过键盘输入一些数据,输入的数据被程序处理完,然后将结果显示在输出设备(显示器,终端等)。
在Linux C环境进行I/O操作有两种方式:
- 标准I/O
- 文件I/O
标准I/O由ANSI C标准定义,C标准中定义了C库,标准I/O就是C库中用来输入和输出的函数。标准I/O在系统调用的上一层多加了一个缓冲区,通过缓冲机制减少了系统调用,实现更高的效率。
程序运行两种方式
无OS
在硬件上直接运行用户代码,这种方式用户代码可以直接操作硬件,只要知道地址,就可以通过指针访问寄存器等等。这种方式一般叫裸机,例如单片机开发。
有OS
在硬件之上,首先运行的是操作系统,操作系统也是一种软件,用来管理各种资源,操作系统提供了对硬件的保护,所有对硬件的操作,必须由操作系统来完成。
通过操作系统提供的系统调用的接口来访问硬件时,应用程序向操作系统发请求,由操作系统来处理这些请求,来完成对硬件的实际操作,并且把结果返回给应用程序。这层接口叫系统调用,不同操作系统接口互不兼容。
标准I/O-流
I/O操作的对象文件,每一个文件有文件名,路径。
不同的操作系统,文件类型不同,Linux文件类型:
- 常规文件 -
- 目录文件 d
- 字符设备文件 c(例如屏幕等串口设备)
- 块设备文件 b(例如硬盘、光驱等)
- 管道文件 p
- 套接字文件 s
- 符号链接文件 I (类似Windows的快捷方式)
FILE
流可以理解为一个FILE结构体,包含于#include <stdio.h>里。FILE就是标准I/O中用来代表一个打开的文件的相关信息:实际I/O的文件描述符,指向流缓存的指针,缓存长度,当前在缓存中的字节数,出错标志等。
标准I/O的所有操作都是围绕FILE来进行操作的,一个FILE结构体代表一个打开的文件。
流(stream)
FILE结构体又称作流(stream)
流分为两种不同的类型:文本流、二进制流。不同的操作系统文本流和二进制流定义不一样,Windows下文本流和二进制流的换行符处理不一样,文本流:换行符 ‘\r’ ‘\n’;二进制流:换行符 ‘\n’。Linux下不区分二者,或者Linux下只有二进制流:换行符: ‘\n’。
标准I/O-流的缓冲类型
全缓存。当标准I/O缓冲区无数据(读)或无空间(写)时才执行实际I/O操作,在标准I/O里,打开一个普通文件时,默认的缓冲类型就是全缓冲。
行缓存。当在输入和输出中遇到换行符(‘\n’)或缓冲区满时,进行实际I/O操作,行缓冲典型的例子就是标准输入(stdin)和标准输出流(stdout)。
当流和一个终端关联时,典型的行缓冲。
无缓存。数据直接写入文件,流不进行缓冲,当打印错误信息时都没有缓冲,直接显示在终端上。stderr通常是无缓存的,因为它必须尽快输出。
标准I/O预定义了3个流,程序运行时系统自动打开,这三个流在程序中可以直接使用,这三个流对应三个文件描述符。
标准输入流 | 0 | STDIN_FILENO | stdin |
---|---|---|---|
标准输出流 | 1 | STDOUT_FILENO | stdout |
标准错误流 | 2 | STDERR_FILENO | stderr |
打开一个标准I/O流:
#include<stdio.h>
FILE *fopen(const char *path,const char*mode)
path:
是一个字符串,包含欲打开的文件路径及文件名
mode参数:
"r"
和"rb"
打开一只读的文件,文件必须存在
"r+"
和"rb+"
+表示可读可写,打开可读写的文件,文件必须存在
"w"
和"wb"
以只写方式打开文件,若文件存在则文件长度清为0,若文件不存在则创建
"w+"
和"wb+"
以读写方式打开文件,若文件存在则文件长度清为0,若文件不存在则创建
"a"
和"ab"
以只写方式打开文件,若文件不存在则创建,向文件写入的数据被追加到文件末尾
"a+"
和"ab+"
以读写方式打开文件,若文件不存在则创建,向文件写入的数据被追加到文件末尾
当给定"b"参数时,表示以二进制方式打开文件,但Linux下忽略该参数。
打开一个标准I/O流的六种不同方式
限制 | r | w | a | r+ | w+ | a+ |
---|---|---|---|---|---|---|
文件必须已存在 | * | * | ||||
擦除文件以前的内容 | * | * | ||||
流可以读 | * | * | * | * | ||
流可以写 | * | * | * | * | * | |
流只可在尾端处写 | * | * |
关闭流
#include <stdio.h>
int fclose( FILE *stream );
函数fclose()关闭给出的文件流, 流关闭时自动刷新缓冲区中的数据并释放缓冲区
fclose()执行成功时返回0,否则返回EOF,并设置errno
程序中能够打开的文件或流的个数有限制
Linux能够打开流或文件的个数是1021+stdin+stdout+stderr = 1024
处理错误信息
extern int errno;
void perror(const char *s);
char *strerror(int errno);
全局变量errno,存放错误号
perror函数先打印字符串s,再输出错误号对应的错误信息
sterror函数根据其参数错误号返回对应错误信息的字符串首地址