一.基础知识
stdio.h:标准头文文件(输入输出)
头文件:从源文件中引入代码,包括类、变量、常量等的声明和定义,以.h结尾,可以使用预处理指令#include引入源代码中
stdio包含的文件:scanf,printf,output,getchar,puts,gets
intput:终端-------------程序(入)
output:程序----------终端(出)
IO分类:
标准IO:库函数
非标准IO(文件IO):系统调用
关系式:标准IO=非标准IO(文件IO)+缓冲区
区别:
系统调用:没调用一次就会进行一次系统调用,效率低(内核空间提供的函数)
标准IO:给输入输出一个缓冲区,缓冲区刷新时会进行一次系统调用,效率高(程序库中的函数)
与现实生活举例:
一个团队20个人去团建,缓冲区相当于一个大巴车,系统调用相当于一个人打一辆车去目的地,而标准IO相当于20个人坐一辆大巴车去目的地,对于个人来言系统调用会快一点,而对于整个团队来说标准IO会快一点
常用的标准IO/系统调用
标准:printf、scanf .putchar.getchar.puts.gets---------------对终端(简单理解:显示在终端)
fopen.fputs.fgets.fputc.fgetc.fprintf.fscanf.fread.fwrite.fclose.fseek--------对文件(简单理解显示在文件中)
文件IO:open.read.write.close
标准文件的关系图:
文件结构体类型:FILE
特殊文件指针:(自动定义过的)
1>stdin:标准输入(scanf)----------文件描述符0
2>stdout:标准输出(printf)---------文件描述符1
3>stderr:标准出错 ----------------------文件描述符2
记忆:std:标准in:入out:出先输入后输出再出错012
NO1:fopen(打开文件【打开哪里的文件,以什么方式打开】)
char:表示文件的路径和方式为字符串
方式:
r:只读,指针在开头
w:只写,不存在创建,存在清空,指针在开头
a:追加(结尾写),不存在创建,存在结尾写,指针在结尾
r+:读写,指针在开头
w+:读写,不存在创建,存在清空,指针在开头
a+:以读/追加,不存在创建,读在开头,写在结尾
总结:读时无需考虑文件是否存在,从开头读,写时,需要考虑,否则文件不存在无法写,实际上可以理解为写就是在结尾写只不过清空后本身的开头和结尾都一样,只写时,需要清空,而追加是无需更改内容,在文件内容后写
NO2:fclose(关闭文件)
EOF:End-of-File文件末尾,特殊常量,其值为1
关于错误码的问题
错误码就是文件IO或者标准IO调用相关函数接口时内核层向用户层传递的一个错误信息,没每个错误码对应的错误信息不同
错误码的种类:
5#define EPERM 1 /* Operation not permitted */不允许操作
6 #define ENOENT 2 /* No such file or directory */没有这样的文件或目录
7 #define ESRCH 3 /* No such process */没有这样的过程
8 #define EINTR 4 /* Interrupted system call */系统调用中断
9 #define EIO 5 /* I/O error */进程错误
10 #define ENXIO 6 /* No such device or address */没有这样的设备或地址
11 #define E2BIG 7 /* Argument list too long */参数列表太长
12 #define ENOEXEC 8 /* Exec format error */执行格式错误
13 #define EBADF 9 /* Bad file number */文件编号错误
14 #define ECHILD 10 /* No child processes */无子进程
15 #define EAGAIN 11 /* Try again */再试一次
16 #define ENOMEM 12 /* Out of memory */内存不足
17 #define EACCES 13 /* Permission denied */权限被拒绝
18 #define EFAULT 14 /* Bad address */地址错误
19 #define ENOTBLK 15 /* Block device required */需要块设备
20 #define EBUSY 16 /*Device or resource busy */设备或资源繁忙
21 #define EEXIST 17 /*File exists */文件存在
22 #define EXDEV 18 /* Cross-device link */跨设备链接
23 #define ENODEV 19 /* No such device */没有这样的设备
24 #define ENOTDIR 20 /* Not a directory */不是目录
25 #define EISDIR 21 /* Is a directory */是一个目录
26 #define EINVAL 22 /* Invalid argument */参数无效
27 #define ENFILE 23 /* File table overflow */文件表溢出
28 #define EMFILE 24 /* Too many open files */打开的文件过多
29 #define ENOTTY 25 /* Not a typewriter */不是打字机
30 #define ETXTBSY 26 /* Text file busy */文本文件繁忙
31 #define EFBIG 27 /* File too large */文件太大
32 #define ENOSPC 28 /* No space left on device */设备上没有剩余空间
33 #define ESPIPE 29 /* Illegal seek */非法寻求
34 #define EROFS 30 /* Read-only file system 0*/只读文件系统 0
35 #define EMLINK 31 /* Too many links */链接过多
36 #define EPIPE 32 /* Broken pipe */断管
课上代码:
#include<stdio.h>
int main(int argc, const char *argv[])
{
FILE *fp = NULL; //定义一个文件指针
//fp = fopen("./01test.txt", "r"); //以只读的形式打开当前目录下的一个文件
//fp = fopen("./01test.txt", "r+"); //以读写的形式打开当前目录下的一个文件
//fp = fopen("./01test.txt", "w"); //以只写形式打开当前目录下的一个文件
//fp = fopen("./01test.txt", "w+"); //以读写的形式打开当前目录下的一个文件
fp = fopen("./01test.txt", "a"); //以读的形式打开当前目录下的一个文件
if(NULL == fp)
{
printf("文件打开失败\n");
return -1;
}else
{
printf("文件打开成功\n");
}
fclose(fp); //关闭fp指针打开的文件
return 0;
}
NO3:strerror(错误码处理函数)
注意:这里用到了errno需要加头文件<errno.h>
课上代码:
#include<stdio.h>
#include<errno.h>
#include<string.h> //strerror函数对应的头文件
int main(int argc, const char *argv[])
{
FILE *fp = NULL; //定义一个文件指针
fp = fopen("./01test.txt", "r"); //以只读的形式打开当前目录下的一个文件
//fp = fopen("./01test.txt", "r+"); //以读写的形式打开当前目录下的一个文件
//fp = fopen("./01test.txt", "w"); //以只写形式打开当前目录下的一个文件
//fp = fopen("./01test.txt", "w+"); //以读写的形式打开当前目录下的一个文件
//fp = fopen("./01test.txt", "a"); //以读的形式打开当前目录下的一个文件
if(NULL == fp)
{/*
printf("文件打开失败\n");
printf("%d\n", errno);
printf("%s\n", strerror(errno)); //输出错误码对应的错误信息
*/
perror("fopen error"); //无需加冒号,自动换行
//fopen error:No such file or directory
return -1;
}else
{
printf("文件打开成功\n");
printf("%d\n", errno);
printf("%s\n", strerror(errno)); //输出错误码对应的错误信息
}
fclose(fp); //关闭fp指针打开的文件
return 0;
}
NO4:perror(第二个处理错误码函数)
NO5:fputs(字符的输入)
NO6:fgetc(字符的输出)
课上代码:
1.使用fgetc来统计一下给定文件的行号
#include<myhead.h>
int main(int argc, const char *argv[])
{
//argc是外部传参的参数个数
//argv:是一个字符串指针数组,表示的是传入参数字符串的地址
if(argc != 2)
{
printf("input file error\n");
printf("usage:./a.out fileName\n");
return -1;
}
//定义文件指针
FILE *fp;
//以只读的形式打开文件
if((fp=fopen(argv[1], "r")) == NULL)
{
perror("fopen error");
return -1;
}
//读取文件中的字符,并判断是否为换行
char buf;
int count = 0; //记录行数
while((buf=fgetc(fp)) != EOF)
{
//对buf进行判断
if(buf == '\n')
{
count++;
}
}
//关闭文件
fclose(fp);
printf("您给的文件一共有%d行\n", count);
return 0;
}
2> 使用fgetc和fputc完成两个文件内容的拷贝工作
#include<myhead.h>
int main(int argc, const char *argv[])
{
//判断是否传入两个文件
if(argc != 3)
{
printf("intput file error\n");
printf("usage: ./a.out srcfile dstfile\n");
return -1;
}
//以只读的形式打开源文件
FILE *srcfp;
if((srcfp = fopen(argv[1], "r")) == NULL)
{
perror("srcfile open error");
return -1;
}
//以只写的形式打开目标文件
FILE *dstfp;
if((dstfp=fopen(argv[2], "w")) == NULL)
{
perror("dstfile open error");
return -1;
}
//定义搬运工
char buf;
while((buf=fgetc(srcfp)) != EOF)
{
//将数据写入目标文件中
fputc(buf, dstfp);
}
//关闭文件指针
fclose(srcfp);
fclose(dstfp);
printf("拷贝成功\n");
return 0;
}
NO7:fputs(字符串的输入)
NO8:fgets(字符串的输出)
课上代码:
#include<myhead.h>
int main(int argc, const char *argv[])
{
//定义文件指针
FILE *fp;
//以只写的形式打开文件
if((fp=fopen("./08test.txt", "w+")) == NULL)
{
perror("fopen error");
return -1;
}
//向文件中写入一个字符串
fputs("Good Good Study\n", fp);
fputs("Day Day Up\n", fp);
//关闭文件
fclose(fp);
//以只读的形式打开文件
if((fp=fopen("./08test.txt", "r")) == NULL)
{
perror("fopen error");
return -1;
}
//定义一个buf
char buf[5];
while(fgets(buf, sizeof(buf), fp) != NULL)
{
printf("%s", buf);
printf("111111111111111111111111111\n");
}
//关闭文件
fclose(fp);
return 0;
}
关于缓冲区大小问题:
1>行缓存:和终端相关的文件的缓冲区(stdin/stdout)/1024字节;
2>全缓存:和文件相关的文件缓冲区(fp)/4096字节;
3>不缓存:和出错相关的文件缓冲区,是没有缓冲区的(stderr),大小为0;
NO9:fflush(刷新缓存区)
行缓冲区刷新:课上代码
#include<myhead.h>
int main(int argc, const char *argv[])
{
//printf("hello world"); //缓冲区的刷新时机未到,不会进行刷新
//while(1);
//1、当遇到换行时,会自动刷新行缓存
//printf("hello world\n");
//while(1);
//2、当程序结束时,会自动刷新行缓存
//printf("ni hao");
//3、当输入输出发生切换时;也会刷新行缓存
//int num;
//printf("请输入num的值:");
//scanf("%d", &num);
//4、当关闭文件指针时会刷新行缓存
//printf("Good Morning");
//fclose(stdout); //关闭标准输出文件指针
//while(1);
//5、当缓冲区满了后会刷新
//for(int i=0; i<1025; i++)
//{
// printf("A");
//}
//while(1);
//6、使用刷新函数进行刷新缓冲区时
printf("hello world");
fflush(stdout); //刷新给定的文件缓冲区
while(1);
return 0;
}
全缓冲区刷新(课上代码)
#include<myhead.h>
int main(int argc, const char *argv[])
{
//printf("hello world"); //缓冲区的刷新时机未到,不会进行刷新
//while(1);
//1、当遇到换行时,会自动刷新行缓存
//printf("hello world\n");
//while(1);
//2、当程序结束时,会自动刷新行缓存
//printf("ni hao");
//3、当输入输出发生切换时;也会刷新行缓存
//int num;
//printf("请输入num的值:");
//scanf("%d", &num);
//4、当关闭文件指针时会刷新行缓存
//printf("Good Morning");
//fclose(stdout); //关闭标准输出文件指针
//while(1);
//5、当缓冲区满了后会刷新
//for(int i=0; i<1025; i++)
//{
// printf("A");
//}
//while(1);
//6、使用刷新函数进行刷新缓冲区时
//printf("hello world");
//fflush(stdout); //刷新给定的文件缓冲区
//while(1);
/*******************************************************/
FILE *fp;
if((fp=fopen("./01test.txt", "w")) == NULL)
{
perror("fopen error");
return -1;
}
//1、遇到换行不会刷新全缓存
//fputs("hello world\n", fp);
//while(1);
//2、程序结束后,会刷新全缓存
//fputs("hello world", fp);
//3、当输入输出切换时,会刷新全缓存
//fputs("ni hao", fp);
//fgetc(fp);
//4、当关闭文件时,会刷新全缓存
//fputs("Good morning", fp);
//fclose(fp);
//5、当缓冲器满了后,会自动刷新全缓存
//for(int i=0; i<4097; i++)
//{
// fputc('H', fp);
//}
//while(1);
//6、当使用fflush时,会刷新缓冲器
fputs("hello world", fp);
fflush(fp);
while(1);
while(1);
return 0;
}
NO10:fprintf(对文件的格式化输入)类似于printf