1 标准IO介绍及缓冲区
1.1 标准IO介绍
- Linux IO进程课程目的:学习编写linux应用程序(APP)
- Linux文件的种类 :
常规文件
目录文件
字符文件
块文件
链接文件(相当于windows快捷方式) - IO的概念
I input 输入设备 比如键盘鼠标都是Input设备
O output 输出设备 比如显示器
优盘,网口,既是输入也是输出
1.1.1文件基础
概念:
一组相关数据的有序集合
文件类型:
- 常规文件 r
- 目录文件 d
- 字符设备文件 c
- 块设备文件 b :U盘 flash块存储
- 管道文件 p
- 套接字文件 s
- 符号链接文件 l
1.1.2 系统调用和库函数
- 系统调用就是操作系统提供的接口函数.
- 如果我们把系统调用封装成库函数就可以起到隔离的作用,提供程序的可移植性。
- printf就是库函数然后调用了系统调用才在显示器上显示字符。

1.1.3 标准I/O
标准I/O由ANSI C标准定义
主流操作系统上都实现了C库
标准I/O通过缓冲机制减少系统调用,实现更高的效率
1.1.3.1 标准I/O-流
FILE
标准IO用一个结构体类型来存放打开的文件的相关信息
标准I/O的所有操作都是围绕FILE来进行
流(stream)
FILE又被称为流(stream)
文本流/二进制流
1.1.3.2 标准I/O-文本流、二进制流
Windows
二进制流: 换行符 '\n'
文本流: 换行符 '\r' '\n'
Linux
换行符 '\n'
1.1.3.3 标准I/O -- 流的缓冲类型
全缓冲
当流的缓冲区无数据或无空间时 才执行实际I/O操作
行缓冲
当在输入和输出中遇到换行符 ('\n')时,进行I/O操作
当流和一个终端关联时,典型的行缓冲
无缓冲
数据直接写入文件,流不进行缓冲
1.1.3.4 三种标准IO

1.1.4 总结
- 流的缓冲类型
- stdin / stdout / stderr
- stdin/stdout 默认是行缓冲
- stderr没有缓冲
- 写代码显示缓冲区大小
1.2 缓冲区实验
buff.c 代码
程序正常结束会刷新缓冲区。
- Sleep函数:是释放cpu给其他应用程序使用的库函数。使用的头文件是#include <unistd.h>
- 查看头文件方法:man 2 函数 ,或者 man 3 函数
c
man 3 sleep

- 标准IO库中,全缓冲 的默认缓冲区大小通常定义为BUFSIZ(在<stdio.h>中),大多数系统下为4096字节,以提高磁盘IO效率。
- 行缓冲(如终端设备)的默认大小通常与终端行长度相关(如1024字节)
2 文件的打开和关闭概念
打开就是占用资源
关闭就是释放资源
2.1 文件的打开
- 文件的打开函数
c
FILE *fopen (const char *path, const char *mode);
Path: 普通文件当前路径不需要加目录,其他要使用完整的路径
Mode:返回值:出错返回NULL,所以使用fopen函数必须判断是否为空
-
文件打开的模式
mode(非常重要)


-
编译错误:
- error: 'errno' undeclared 表示errno变量没有定义
解决方法:如果是系统变量用include 头文件,如果是你自己的,自己手动定义。
bash
f_open.c:9:38: error: 'errno' undeclared (first use in this function)
printf("fopen:%s\n",strerror(errno));
- warning: implicit declaration of f unction 'strerror' 表示strerror函数隐示的声明
解决方法:include 添加对应的头文件。
bash
f_open.c:10:29: warning: implicit declaration of function 'strerror' [-Wimplicit-function-declaration]
printf("fopen:%s\n",strerror(errno));
- perror 库函数 头文件stdio.h
strerror 库函数 头文件 errno.h string.h
perror和strerror 功能:打印系统的错误描述(注意:是系统错误,不是你自己代码错误)
- perror自动读取全局变量errno的值,无需手动传入错误码;而strerror需通过参数指定错误码(如strerror(errno))
- perror将错误信息输出到标准错误输出(stderr),而非stdout;strerror仅返回错误描述字符串,需配合其他函数(如printf)输出到指定位置
- perror的调用格式为perror("自定义提示"),输出结果为"自定义提示: 系统错误描述";strerror直接返回系统错误描述字符串(如"Permission denied"),需用户自行拼接额外信息
c
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, char const *argv[])
{
// FILE* fp = fopen("lala.txt","r");
// FILE* fp = fopen("lala.txt","w");
FILE* fp = fopen("lala.txt","a");
if(!fp){
perror("fopen");//fopen: No such file or directory
printf("fopen:%s\n",strerror(errno));
}else{
printf("Open file succuss\n");
}
}
2.2 文件的关闭
函数原型:int fclose(FILE *stream)
- fclose()调用成功返回0,失败返回EOF(-1),并设置errno
- 流关闭时自动刷新缓冲中的数据并释放缓冲区 ,比如:常规文件把缓冲区内容写入磁盘
- 当一个程序正常终止时,所有打开的流都会被关闭
- fclose()函数的入参stream必须保证为非空,否则出现段错误。
c
if(fclose(fp) == 0){
printf("fclose file succuss\n");
}else{
perror("fclose");
}
3 标准IO的读写(字符、行)
3.1 读写单个字符
3.1.1 字符的输入(读单个字符):
c
int fgetc(FILE *stream);
int getc(FILE *stream); //宏
int getchar(void);
成功时返回读取的字符;若到文件末尾或出错时返回EOF(-1),
getchar()等同于fgetc(stdin)
getc和fgetc区别是一个是宏一个是函数
注意事项:
- 函数返回值是int类型不是char类型,主要是为了扩展返回值的范围。
- tdin 也是FILE *的指针,是系统定义好的,指向的是标准输入(键盘输入)
- 打开文件后读取,是从文件开头开始读。读完一个后读写指针会后移。读写注意文件位置!
- 调用getchar会阻塞,等待你的键盘输入
3.1.2 字符的输出(写单个字符):
c
int fputc(int c, FILE *stream);
int putc(int c, FILE *stream);
int putchar(int c);
成功时返回写入的字符;出错时返回EOF
putchar©等同于fputc(c, stdout)
注意事项:
- 返回和输入参数都是int类型
- 遇到这种错误:Bad file descriptor, 很可能是文件打开的模式错误(只读模式去写,只写模式去读)
3.2 按行输入文件(读取整个行)
c
char *gets(char *s); 读取标准输入到缓冲区s
char *fgets(char *s, int size, FILE *stream);
成功时返回s,到文件末尾或出错时返回NULL
遇到'\n'或已输入size-1个字符时返回,总是包含'\0'
注意事项:
- gets函数已经被淘汰,因为会导致缓冲区溢出
- fgets 函数第二个参数,输入的数据超出size,size-1个字符会保存到缓冲区,最后添加'\0',如果输入数据少于size-1 后面会添加换行符。
3.3 按行输出文件(写整个行)
c
int puts(const char *s);
int fputs(const char *s, FILE *stream);
成功时返回非负整数;出错时返回EOF
puts将缓冲区s中的字符串输出到stdout,并追加'\n'
fputs将缓冲区s中的字符串输出到stream,不追加 '\n'