- 什么是IO?
Input:输入
Output:输出
我们之前学习过的scanf、printf、getchar、putchar、gets、puts这些都是标准输入输出
标准输入:数据从键盘拷贝到内存
标准输出:数据从内存拷贝到显示屏
笼统的输入和输出:
输入:数据从文件拷贝到内存--》读文件
输出:输出从内存拷贝到文件--》写文件
- 标准IO
2.1什么是标准IO
(1)标准:ANSI C的标准
(2)标准IO:ANSI C标准提供的一系列用来进行输入和输出的函数
(3)只要操作系统有c库就可以使用标准IO
(4)标准IO有缓存区
(5)标准IO在系统调用之上构造的
2.2文件的概念
2.3什么是缓存区,什么是系统调用
系统调用:内核给应用程序留的接口(函数)
标准IO有缓冲区,文件IO没有缓冲区,有缓冲区可以减少系统调用的次数,系统的开销就会减少
全缓存:缓冲区满、强制刷新、文件关闭、程序结束时刷新缓冲区
行缓存:遇到换行符、缓冲区满、强制刷新、文件关闭、程序结束时刷新缓冲区
不缓存:没有缓存区
打开文件,就会有缓冲区产生,就会有流存在,所以我们也说打开了流,读文件也叫对流进行读操作,写文件也叫对流进行写操作,关闭文件也叫关闭流。
或者我们说对流进行读写操作,实际上也是对文件进行读写操作。
总结:对流的操作就是对文件的操作
打开一个文件,就会有缓冲区产生,也会有一个FILE类型的变量的产生,这个FILE类型是一个结构体,用来描述一个打开的文件(一个打开的流)的详细信息,所以如何操作文件(流)就是通过指向这个结构体变量的指针来操作的
FILE *的指针其实是操作文件(流)的handle(句柄)
打开文件:FILE *类型指针产生
读写文件关闭文件:用FILE*类型的指针来操作
2.4、标准IO相关函数
注意:不需要刻意去记忆这些函数,需要用的时候去查,多用用就熟了,我们需要做的是理解流程,也就是在哪里需要用到这些函数以及用的时候流程是什么。
Fopen fread fgetc fgets fwrite fputc fputs fclose fseek ftell
- Fopen
功能:打开一个文件(流)
参数:1、文件的路径 2、打开方式
返回值:成功:文件流指针 失败:NULL
- 对文件(流)进行读写操作
- 按字符读写(fgetc、fputc)--》文本文件
Feof函数可以测试是否到达文件末尾(文件末尾是有结束标志的),如果是文件结束标志就返回非0,如果返回值为0,就表示没有到文件末尾
参数:c 要写入文件的字符的ASCII值
Stream 要操作的流
返回值:成功 c
失败 -1
- 按行(字符串)读写(fgets、fputs)--》文本文件
功能:从stream中读字符串,将读到的字符串存放在地址为s,大小为size的这块空间中
返回值:什么时候会返回?
- 当读到换行符的时候会返回,并且换行符也会被读到,还不够size-1个字节
- 没有遇到换行符,读够了size-1个就会返回
因为最后要存放’\0’
所以:fgets比gets更安全,因为fgets最多读size-1个,而gets读了size个也可以
Fgets会将’\n’也读入,而gets不会
失败或者读完就返回NULL,否则就返回s
注意:fputs和puts的区别?
- fputs可以输出到制定的任何流,puts只能输出到标准输出流
- Fputs输出不会自动加’\n’,puts输出会加’\n’
- 按块读写(fread、fwrite)--》文本文件、二进制文件
参数:ptr 内存的首地址
Size 每一块的大小
Nmemb 块数
Stream 流
所以:最终写入和读出的字节数=size*nmemb
返回值:成功 成功读出或者写入的块数
比如:10 5 每次会读50个字节
假设文件的大小是155字节
需要读四次,前三次每一次都会读50个字节,最后一次只会读5个字节
此时返回值是15,因为剩下的5个字节不足一个块
所以我们一般为了通过返回值就能够知道读到或者写入了多少个字节,块大小=1,块数=sizeof(buf),所以返回值就能够表示读或写的字节数
- 流的定位
打开了流(文件),文件是有当前的读写位置的,刚刚打开文件的时候读写位置就是0,如果往文件里写了10个字节,那么文件的当前读写位置就会变成10,下次再要读写文件就从10这个位置开始
- 文件IO
文件IO:linux系统提供的一系列用来进行输入和输出的函数(系统调用)
- Open
功能:打开一个文件,如果文件存在,就打开文件,如果文件不存在,就创建并打开文件
参数:1、文件路径 2、打开方式 3、新创建的文件的权限
最终新创建的文件的权限=mode & ~umask,所以第三个参数一般传0666
如果不创建文件,open就传两个参数,如果需要创建文件,第二个参数| O_CREAT,并且第三个参数传0666
返回值:-1 失败 并设置errno
成功 非负整型数(文件描述符),最小的未用的
最小的未用的:
0 1 2已经被占用,如果open打开文件至少返回3,再打开一个就返回4,再打开一个就返回5,假设现在3被关闭了,3就不用了,再打开一个文件就返回3
- Read
功能:通过文件描述符读文件内容
参数:fd:open的返回值
Buf:内存空间的首地址
Count:要读的字节数,一般就是buf的大小
返回值:-1 失败 成功:实际读到的字节数
- Write
同上
练习:定义一个学生的结构体类型,将这个学生的信息写入文件,然后用另外一个程序得到学生的信息并打印
空洞文件:
比如要下载一个大的文件,先在本地创建一个和要下载的文件大小一样的空洞文件,先将空间占上,防止下载一半空间不足导致下载失败
0000400
0100664
- 目录的操作
注意:读一次只能获得目录中的一个文件的信息,要想获得所有文件的信息,需要一直读,直到返回NULL
- 库的制作
库是一种可执行代码的二进制形式
库中有很多定义好的函数,我们的程序可以调用这些函数,调用的时候需要链接到这个库(需要将库加载到我们的代码中)
静态库和动态库:
库的命名:
前缀lib
后缀:静态库.a 动态库.so
制作静态库:
其中:-L路径 -l库名
制作动态库:
如果用的是动态库,运行的时候因为a.out中没有加载动态库,所以运行时找不到库就失败
怎么办?
- 将动态库拷贝到/lib或者/usr/lib目录下,因为系统会默认在这两个目录下找动态库
- 告诉系统运行的时候到你指定的目录下找动态库