课程分为三部分:IO文件-动态库、静态库制作,进程(本地进程间通信),线程(线程通信)
特点:学习大量的函数接口调用-函数名及功能、man手册查看参数
一、IO介绍
1、概念
对文件的输入输出。I :input O:output
读文件:将文件中的内容读到内存中进行处理
写文件:将内存中的内容写到文件中
文件是存放到磁盘空间上的,掉电文件不丢失
2、linux文件类型:
b(块设备文件)
c(字符设备文件)
d(目录文件)
-(普通文件)
l(链接文件)
s(套接字文件)网络编程
p(管道文件)
二、文件IO和标准IO区别
总结:
标准IO:是c库提供的输入输出函数接口。不同的操作系统都可以使用,只要有库就行。是在系统调用之前做了一个二次封装,间接进行了系统调用。
文件IO:内核向上提供的输出输出函数接口,叫做系统调用函数接口。基于内核,内核不同,系统调用函数接口不同,文件IO不同操作系统函数接口不通用。
fread-标准IO的函数接口
{
if(是linux)
{
//调用linux的系统调用函数接口
read();
}
else if(是windows)
{
_read();
}
else if(是mac)
{
Read();
}
}
标准IO在系统调用之前做二次封装增加缓存机制 ,减少了系统调用次数,提高效率。
-
三、标准IO
1.标准I/O
标准IO是指在C库中提供的一组专门用于输入输出的函数
标准I/O由ANSI C标准定义不仅在UNIX系统,在很多操作系统上都实现了标准I/O
标准I/O通过缓冲机制减少系统调用,实现更高效率
标准I/O库的所有操作都是围绕流(stream)来进行的,在标准I/O中,流用FILE *来描述。
标准IO默认打开了三个流:stdin、stdout、stderr-->标准输入、标准输出、标准出错
2. 文件 I/O man 2
是有linux内核提供的接口函数
这些操作往往都会涉及到 对硬件的操作,
磁盘运行速度比较慢,因此要减少磁盘的
读写次数,没有缓冲机制。
增加每次续写的量 ,也就是减少
read write 函数的调用次数。
四、流
定义:所有的I/O操作仅是简单的从程序移进或者移出,这种字节流,就称为流。
分类:文本流/二进制流。
流指针:FILE *
每个被打开的文件都在内存中开辟一个区域,
用来存放文件的有关信息,这些信息是保存在一个
结构体类型的变量中,该结构体类型是由系统定义的,
取名为FILE。
查看结构体:FILE 追踪软件ctags
vi -t FILE
typedef struct _IO_FILE FILE;
ctrl ’]‘ :追踪
ctrl ’t‘ :返回:
用结束地址减去起始地址可以得到缓存区大小:
char* _IO_buf_base; /* 缓存区的起始地址 */
char* _IO_buf_end; /* 缓存器的结束后地址 */
围绕“流”进行操作,“流”用FILE*表示。
- FILE是数据类型(结构体),FILE*结构体指针。
- 文件内部有文件指针,文件用文件指针操作,流只是起到了一个媒介的作用,封装原来的接口等,开辟缓冲区,减少系统调用。
- 索引使用:1.vi -t要查找的内容 (查找宏,数据类型等)
输入前面序号,回车
- 继续追踪
将光标定位到要追踪的内容上,ctrl+] (右中括号)
回退:ctrl+t
3)标准IO默认打开了三个流,stdin(标准输入)、stdout(标准输出)、stderr(标准错误)
三个流是结构体指针变量。
4)标准IO一般只用于操作普通文件
五、标准I/O常见函数
1. fopen / fclose 打开文件 关闭文件
2. fgetc / fputc 读一个字符/写一个字符
3. fgets / fputs 读一个字符串/写一个字符串
4. fwrite/ fread 读写一个二进制文件
5. fseek 移动文件指针(光标)函数
-
六、缓冲区分类
注意:缓存区是在使用的时候才会开辟
1.全缓存 -->fopen打开的文件都是全缓存
刷新全缓存:
1.程序正常退出
2.fflush强制刷新缓存
3.遇到return (main)
4.exit退出进程
5.关闭fclose流指针
6.缓存区满
2.行缓存 -->基于终端:stdin\stdout
刷新缓存区:
1.'\n'刷新
2.程序正常退出
3.fflush强制刷新缓存
4.遇到return (main)
5.exit退出进程
6.关闭fclose流指针
7.缓存区满
注意:当遇到阻塞输入函数时,输出缓存区会刷新
3.不缓存: stderr
行缓存区大小计算:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
//计算行缓存的大小
/* for(int i=1;i<300;i++)//256*4=1024 = 1KB
{
printf("%4d",i);
}*///缓存区满计算
//缓存区首尾地址之差
printf("hello world.");//缓存区使用时开辟
printf("size:%d\n",stdout->_IO_buf_end-stdout->_IO_buf_base);
while(1);
return 0;
}
fflush函数:
查看错误码 vi -t EEXIST
#include <stdio.h>
int fflush(FILE *stream);
功能:刷新缓存区
参数:
stream:流 (NULL:刷新所有流)
返回值:成功 0
失败:返回错误码 EOF(-1),更新errno。
七、缓冲机制
1)全缓冲:跟文件相关
刷新条件:
程序正常结束
缓冲区满刷新
强制刷新:fflush
2)行缓冲:跟终端相关
刷新条件:
\n
程序正常结束
缓冲区满刷新
强制刷新:fflush
#include <stdio.h>
int main(int argc, char const *argv[])
{
//1.\n刷新缓冲区
// printf("hello world\n");
// while (1)
// ;
//2.程序正常退出
// printf("hello world");
// while (1)
// ;//不让程序结束
//3.缓冲区满刷新
//有大小,当将缓冲区写满数据时,
//再继续向缓冲区中写数据,
//会将原来缓冲区中满了的数据全部拿出来,打印到终端
//新写的数据,可以继续向里面写
//测试缓冲区大小 kb 1kb=1024byte 1b=8bit
//缓冲区大小1kb
//方法一:
// for(int i=0;i<300;i++)
// {
// printf("%4d",i);
// }
// while(1);
//方法二:
//缓冲区的结束地址-起始地址=缓冲区大小
// printf("hello"); //开辟缓冲区
// printf("%d\n", stdout->_IO_buf_end - stdout->_IO_buf_base);
// 4.强制刷新
printf("hello");
//fflush(stdout);//强制刷新
fflush(NULL);//强制刷新所有的输出缓存
while (1)
;
return 0;
}
return 是函数的正常结束
ctrl +c是函数的不正常结束
3)不缓冲:没有缓冲区,标准错误
scanf--》标准输入缓冲区---》终端输入
标准输入缓冲区有内容 不进入终端输入
printf--》标准输出缓冲区---》终端
-
八、标准IO函数接口
1、fopen freopen打开文件
1)fopen 打开文件
FILE *fopen(const char *path, const char *mode)
功能:打开文件
参数:
path:打开的文件路径
mode:打开的方式
r:只读,当文件不存在时报错,文件指针定位到文件开头
r+:可读可写,当文件不存在时报错,文件指针定位到文件开头
w:只写,文件不存在创建,存在清空文件,文件指针定位到文件开头
w+:可读可写,文件不存在创建,存在清空文件,文件指针定位到文件开头
a:追加(在末尾写),文件不存在创建,存在追加,文件指针定位到文件末尾
a+:读和追加,文件不存在创建,存在追加,读文件指针定位到文件开头,
写文件流定位到文件末尾
注:当a的方式打开文件时,写只能在末尾进行追加,定位操作是无法改变写的位置,但是可以改变读的位置
返回值:成功:得到一个文件流指针
失败:NULL,并且会设置错误码
a+:初始读指针在文件开始位置,写指针在文件结束位置,如果只调用读指针,那么读指针从刚开始位置后移,一旦调用写指针,读写指针合二为一,读指针去到写指针的位置
测试:一个任务中最多能打开多少个文件?(一个文件是可以被重复打开)1024个;
-
2、获取错误信息 perror
2.1查看错误码 vi -t EEXIST
void perror(const char *s);
功能:根据errno值获取错误信息,将信息输出到终端
参数:
s:错误信息的内容
返回值:无
-
3、关闭文件:fclose
int fclose(FILE* stream);
功能:关闭文件
参数:stream:文件流
成功:返回0
失败:返回-1,更新erron
4、读写操作
1)fgetc:每次读一个字符
int fgetc(FILE * stream)
功能:从文件中读取一个字符
参数:stream:文件流
返回值:成功:读到的字符ASCII码
失败或读到文件末尾:EOF(-1)
2)fputc:每次写一个字符
int fputc(int c, FILE * stream)
功能:向文件中写入一个字符
参数:c:要写的字符
stream:文件流
返回值:成功:写的字符的ASCII码
失败:EOF(-1)
练习1、用fgetc和fputc完成cp功能
练习2、测试全缓存大小
3)fprintf定向输出到文件中
int fprintf(FILE *stream, const char *format, ...);
功能:向指定的文件以指定的格数写入数据
参数: stream :流指针
format:指定格式
...:多个参数
返回值:输出字符个数
失败返回:EOF
4)fgets:
char * fgets(char *s, int size, FILE * stream);
功能:从文件中每次读取一行字符串
参数:s:存放字符串的地址
size:一次读取的字符个数
stream:文件流
返回值:成功:s的地址
失败或读到文件末尾:NULL
特性:每次实际读取的字符个数为size-1个,会在末尾自动添加\0
每次读一行,遇到\n后不再继续,读下一行
5)fputs
int fputs(const char *s, FILE *stream);
功能:向指定文件中输入一串字符
参数:
s:输入字符串的首地址
stream:文件流指针
返回值:成功返回输出字符个数
失败返回EOF