一、IO简介
1.1 IO的过程
操作系统的概念:向下统筹控制硬件,向上为用户提供接口。
操作系统的组成 = 内核 + 外壳(shell)
linux的五大功能:进程管理、内存管理、文件管理、设备管理、网络管理。
最早接触的IO:
printf -- 标准输出
scanf -- 标准输入
1.2 IO的种类
文件IO(系统调用)和 标准IO(库函数)
1.3 文件IO(系统调用)
系统调用是内核提供的受控入口,我们通过系统调用从用户空间进入内核空间。
系统调用特点:可移植性差、实时性强、效率低。
windows:readfile读取文件
linux:read读取文件
1.4 标准IO(库函数)
库函数 = 系统调用 + 缓冲区
库函数的特点:可移植性强,效率高,实时性差。
(缓冲机制的加入,减少了系统调用的次数,提高程序运行效率。)
1.5 常用的接口
文件IO:open、close、read、write……
标准IO:fopen、fclose、fread、fwrite、fseek……
二、标准IO(库函数)
2.1 FILE指针
FILE是标准库中定义的一个结构体。
FILE指针是一个结构体指针。
FILE指针指向的结构体中包含了打开文件的相关信息,我们通过FILE指针操作文件。
使用fopen函数成功打开一个文件之后,就会获取一个FILE指针。后面对该文件读写操作,都是通过这个指针。
每个正在运行的程序都会维护自己的FILE指针,即使多个程序打开了同一个文件,对应的FILE指针也会不同!
每个正在运行的程序都有三个默认打开的FILE指针:
- 标准输入:stdin
- 标准输出:stdout
- 标准出错:stderr -- perror
struct _IO_FILE
{
char *_IO_buf_bash; /*缓冲区的起始地址*/
char *_IO_buf_end; /*缓冲区的结束地址*/
int _fileno; /*文件描述符*/
};
2.2 fopen (打开文件)
#include <stdio.h> ---- 所需头文件
FILE *fopen(const char *pathname,const char *mode);
功能:打开pathname对应的文件
参数:
pathname:要打开的文件路径和名字
mode:
r:以只读的方式打开文件,将光标定位到文件的开头。
r+:以读写的方式打开文件,光标定位到文件的开头。
w:以只写的方式打开文件,如果文件存在就清空,文件不存在就创建文件。
w+:以读写的方式打开文件,如果文件存在就清空,文件不存在就创建文件。
a:以追加的方式打开文件,光标定位在文件结尾,文件不存在就创建文件。
a+:以追加和读的方式打开文件,如果读 光标在文件的开头,如果写 光标在文件结尾。
文件不存在就创建文件
返回值:成功返回FILE指针,失败返回NULL,置位错误码
fopen使用示例
#include <stdio.h>
int main(int argc, const char *argv[])
{
FILE *fp = NULL;
//1.以只读的方式打开一个文件
fp = fopen("./a.c","r");
if(NULL == fp){
printf("fopen error\n");
return -1;
}
return 0;
}
运行结果:
#include <stdio.h>
int main(int argc, const char *argv[])
{
FILE *fp = NULL;
//2.以只写的方式打开文件:
//文件不存在就创建,文件存在就清空
fp = fopen("./b.c","w");
if(NULL == fp){
printf("fopen error\n");
return -1;
}
return 0;
}
运行结果:
2.3 fclose(关闭文件)
#include <stdio.h> -- 所需头文件
int fclose(FILE *stream);
功能:关闭文件
参数:
stream:FILE指针
返回值:成功返回0,失败返回EOF(-1),置位错误码
fclose使用示例
#include <stdio.h>
int main(int argc, const char *argv[])
{
//1.先正常输出
printf("111\n");
//2.关闭标准输出
fclose(stdout);
//3.再次输出
printf("222\n");
return 0;
}
运行结果:
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a = 0;
//1.先正常输入
scanf("%d",&a);
printf("a = %d\n",a);
//2.关掉标准输入
fclose(stdin);
//3.再输入一次
scanf("%d",&a);
printf("a = %d\n",a);
return 0;
}
运行结果:
2.4 错误码
2.4.1 错误码的概念
错误码就是系统调用失败后,内核向用户返回的错误信息的编号。
错误码是大于0的整数。
在内核中有4K个错误码。
2.4.2 错误的原理
2.4.3 错误码的使用示例
#include <stdio.h>
#include <errno.h>//errno全局变量在这个头文件中
int main(int argc, const char *argv[])
{
FILE *fp = NULL;
//使用fopen打开一个不存在的文件
fp = fopen("./c.txt","r");
if(NULL == fp){
printf("fopen error\n");
printf("errno = [%d]\n",errno);
return -1;
}
//使用fopen打开一个没有权限的文件
fp = fopen("./c.txt","r");
if(NULL == fp){
printf("fopen error\n");
printf("errno = [%d]\n",errno);
return -1;
}
return 0;
}
运行结果:
2.4.4 strerror (将错误码转换为错误信息)
#include <string.h> -- 所需头文件
char *strerror(int errnum);
功能:将错误码转换为错误信息(字符串)
参数:
errnum:错误码
返回值:成功返回错误码对应的错误信息,失败返回“Unknown error nnn”
strerror 使用示例
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, const char *argv[])
{
FILE *fp = NULL;
//打开一个不存在的文件
fp = fopen("c.txt","r");
if(NULL == fp){
printf("fopen error\n");
printf("errno = [%s]\n",strerror(errno));
return -1;
}
return 0;
}
运行结果:
2.4.5 perror直接打印错误信息
#include <stdio.h>
void perror(const char *s);
功能:直接打印错误信息
参数:
错误信息提示,这个字符串后面会自动添加“:” 和 换行
perror使用示例
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(int argc, const char *argv[])
{
FILE *fp = NULL;
//使用fopen打开一个不存在的文件
fp = fopen("./c.txt","r");
if(NULL == fp){
perror("fopen c.txt error");
return -1;
}
return 0;
}
运行结果: