标准IO
【1】系统调用和库函数
系统调用:内核提供的函数接口,比较稳定
库函数:开发人员封装的函数接口,由开发人员提供,如果库有问题,可能会影响代码
【2】IO
IO:input output
bcd-lsp
【3】标准IO和文件IO
标准IO:带缓存的IO
通过库函数的方式对文件进行操作,数据被暂存到缓存区中,直到满足一定条件才会被实时写入
优点:减少系统调用的开销,有利于保护硬件
缺点:数据不会实时写入,可能会丢失
文件IO:不带缓存的IO
通过系统调用的方式对文件进行操作,数据不存在缓存区中,直接实时写入。
优点:实时写入数据,不会丢失
缺点:频繁得同调用,增加系统开销,不利于保护硬件
【4】标准IO
缓存区类型分为三类:
全缓存(默认情况下时全缓存)
刷新条件:
1.缓存区满了
2.程序正常结束(ctrl + c、断电不是正常结束)
3.执行刷新函数
行缓存(和终端有关系的缓存)
刷新条件:
1.遇到\n
2.程序正常结束
3.执行刷新函数
4.缓存区满了
不带缓存(使用较少)
刷新条件:
stderr 标准错误
【课程特点】
1.理论知识-需要理解-会使用
2.记住的东西越多,为自己未来省的事越多
3.模仿的能力
标准IO操作
打开-读写-关闭
【5】流
标准IO的所有操作都是围绕流来进行的,流用FILE *来描述 // int *
【6】ctags
1.安装
sudo apt-get install ctags
2.生成索引文件tags
cd /usr/include/
sudo ctags -R
3.查找内容FILE
vi -t "FILE"
4.继续追加内容
把光标放在要追加的内容上
ctrl + ] 向下一级内容追加
ctrl + t 向上一级内容追加
5.退出
:q
如果只能在/usr/include/下才能执行,请配置.vimrc,在文件结尾添加 set tags+=/usr/include/tags
【7】获得流
#include <stdio.h>
FILE *fopen(const char *path, const char *mode);
功能:打开一个文件,获得流
参数:path 要打开的文件的路径
mode 模式
r 只读的模式,要求文件必须存在
r+ 以读写的模式,要求文件必须存在
w 只写,如果文件不存在则创建
w+ 以读写的模式,如果文件不存在则创建
a 追加写的模式,如果文件不存在则创建
a+ 以读写的模式,如果文件不存在则创建
返回值:成功返回FILE * 失败返回NULL
练习:测试当前系统最多可以打开多少个文件?(1024个)
系统默认打开了三个流
stdin stdout stderr
标准输入 标准输出 标准错误
【8】关闭流
#include <stdio.h>
int fclose(FILE *fp);
功能:关闭流
参数:fp要关闭的流
返回值:成功0,失败EOF
【9】每次一个字符的读写
读:
getchar()
#include <stdio.h>
int fgetc(FILE *stream);
功能:读一个字符
参数:stream 流
返回值:成功返回读到的字符,失败EOF
int getc(FILE *stream);
功能:读一个字符
参数:stream 流
返回值:成功返回读到的字符,失败EOF
区别:fgetc(函数) getc(宏定义)
写:
putchar()
#include <stdio.h>
int fputc(int c, FILE *stream);
功能:向流中写入一个字符
参数:c 同要写入的字符(putchar的参数)
stream 写入的流
返回值:成功返回写入的字符,失败返回EOF
int putc(int c, FILE *stream);
同上
区别:
fputc(函数)
putc(宏定义)
【10】每次一行字符的读写
读:
gets()
有多少读多少,会溢出
#include <stdio.h>
char *fgets(char *s, int size, FILE *stream);
功能:读一行字符
参数;s 读到数据存放的位置
size 一次读的字符多少
stream
返回值:成功返回s的地址,失败返回NULL
区别:gets(宏定义)fgets(函数)
练习:利用fgets函数,测试一个文件有多少行?
写:
puts()
自动加一个换行符
#include <stdio.h>
int fputs(const char *s, FILE *stream);
功能:输出一行字符,不自带换行符
参数:s 要输出的内容
stream
返回值:成功返回成功写的个数,失败EOF
区别:宏定义 函数
【11】直接IO:操作的不再是一个字符,也不是一行字符,而是一条记录
写:
#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
功能:向流中写入一个记录
参数: ptr 要写的内容
size 一条记录的大小
nmemb 执行一次fwrite函数期望要写的记录条数
stream
返回值:成功写入的记录的条数
读:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:从流中读一条记录
参数: ptr 要读的内容存放位置
size 一条记录的大小
nmemb 执行一次fwrite函数期望要写的记录条数
stream 流
返回值:实际读到记录的条数
练习:利用fread、fwrite实现文件copy的功能
cp 源文件 目标文件
思路:
1.获得流-源文件、目标文件 fopen
2.fread从源文件中读
3.fwrite写到目标文件中
4.fclose-源文件、目标文件
【12】time
#include <time.h>
time_t time(time_t *t);
功能:获得1970年1月1日0:0:0到现在的秒数
参数:t 保存秒数
返回值:成功获得的秒数,失败((time_t) -1)
struct tm *localtime(const time_t *timep);
功能:对秒数进行转换
参数:秒数
返回值:成功获得的结果,失败NULL
int fprintf(FILE *stream, const char *format, ...);
功能:向流中打印
使用方法:同printf
【13】刷新流
#include <stdio.h>
int fflush(FILE *stream);
功能:刷新流
参数:stream 流
NULL 刷新所有的输出流
返回值:成功0 失败EOF
【14】标准IO文件的定位和偏移函数
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
功能:对文件访问位置进行偏移
参数:stream 流
offset 偏移量
whence 相对位置
SEEK_SET 文件的开头 SEEK_CUR文件当前位置 SEEK_END 文件的结尾位置
返回值:成功0 失败-1
fseek(fp,-100,SEEK_END) 相对结尾位置向前移动100字节
fseek(fp,100,SEEK_CUR) 相对当前位置向后移动100字节
long ftell(FILE *stream);
void rewind(FILE *stream);
功能:将文件的访问位置偏移到开头
参数:stream 流
long ftell(FILE *stream);
功能:对文件访问位置定位
参数:stream 流;
返回值:成功返回当前位置、失败-1
【15】出错处理
#include <string.h>
char *strerror(int errnum);
功能:出错处理函数
参数:errnum 错误号
返回值:错误原因的字符串
注意:加头文件errno.h
cd /usr/include/asm-generic/ 中查看errno.h errno-base.h
#include <stdio.h>
void perror(const char *s);
功能:出错处理函数,自带换行符
参数:字符串(自己写的)
【总结】标准IO操作的核心-流
文件IO操作的核心-文件描述符
文件描述符:一个非负整数