目录
文件状态指针
文件流
文件的顺序读写
fgetc
fputc
fgets
fputs
fscanf
fprintf
fread
fwrite
今天接下来我们讲解文件读写函数。🆗🆗🆗
文件状态指针
- 文件状态指针也就是文件指示器。(可以理解为光标)
- 文件在不断被操作读取的过程中,文件状态指针是一直在移动的。
文件流
- 流是怎样一个概念呢?我们简单通俗的介绍下。本篇我们把所有输入输出流分为两个标准输入出流和文件流
流是一个高度抽象的概念!!在我们写程序的时候,我们需要将数据传到屏幕,存在硬盘上,传到网络上,U盘光盘等外部设备。不同的外部设备的读写方式不同,传输方式也不同。 有人觉得程序员也太难了,于是抽象化了流的概念。我们先将数据统一传输到流里面(文件流等),然后再传输到各个外部设备。
我们在写文件的时候,需要打开文件,关闭文件。我们用scanf从键盘上读取数据,printf向屏幕上打印数据,直接操作了为什么没有打开标准输入输出流呢?
那是因为C语言程序运行起来,就默认打开了3个流。
- stdin : 标准输入流(键盘)
- stdout : 标准输出流(屏幕)
- stderr : 标准错误流
- 特别提醒:所有的流都是FILE*的指针类型
用打开标准输出流的方式打印26个字母
#include<stdio.h>
int main()
{
char ch = 0;
for (ch = 'a'; ch <= 'z'; ch++)
{
if (ch % 5 == 0)
fputc('\n', stdout);//标准输出流
fputc(ch, stdout);
}
//a-97
//b-98
//c-99
//100换行了
return 0;
}
用打开文件流的方式打印26个字母。------>下面fputc
#include<stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
char ch = 0;
for (ch = 'a'; ch <= 'z'; ch++)
{
if (ch % 5 == 0)
fputc('\n', pf);//文件流
fputc(ch, pf);
}
//a-97
//b-98
//c-99
//100换行了
fclose(pf);
pf = NULL;
return 0;
}
文件的顺序读写
记住:站在内存数据的角度去理解!! 其次文件要用输入输出函数去输入输出操作,别手动键盘修改文本文件,这样达到不到想要的效果哦!!
功能 函数名 适用于
字符输入函数 fgetc 所有输入流
字符输出函数 fputc 所有输出流
文本行输入函数 fgets 所有输入流
文本行输出函数 fputs 所有输出流
格式化输入函数 fscanf 所有输入流
格式化输出函数 fprintf 所有输出流
二进制输入 fread 文件
二进制输出 fwrite 文件
我们接下来详细的介绍以上各个函数。函数头文件 参数 返回值 使用去介绍
fgetc
fgetc - C++ Reference (cplusplus.com)
- fgetc是以读的形式把字符输出文件,内存读取数据。
- 头文件 #include<stdio.h>
- 参数FILE *stream 文件指针类型的指针变量 指向了一个文件信息区
- 返回值是int类型(字符发生了整型提升)
- 成功后,将返回字符读取(提升为 int 值)ASCII码。
- 返回类型为 int 以适应特殊值 EOF,该值表示失败-1
- 如果位置指示器位于文件末尾,则该函数返回 EOF 并设置流的 eof 指示器 (feof)。
- 如果发生其他读取错误,该函数还会返回 EOF,但改为设置其错误指示器 (ferror)。
#include<stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch=fgetc(pf);
printf("%c", ch);
ch=fgetc(pf);
printf("%c", ch);
ch=fgetc(pf);
printf("%c", ch);
ch=fgetc(pf);
printf("%c", ch);
ch=fclose(pf);
pf = NULL;
return 0;
}
fputc
fputc - C++ Reference (cplusplus.com)
- fputc以写的形式输入字符到文件中。
- 头文件#include<stdio.h>
- 参数int character 是整型 也就是字符整型提升 直接写字符即可
- 参数FILE*stream 是文件指针类型的指针变量 指向了一个文件信息区
- 返回值
- 成功后,将返回所写字符(整型提升)。
- 如果发生写入错误,则返回 EOF 并设置错误指示器(ferror)。
#include<stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fputc('a', pf);//文件流
fputc('b', pf);
fputc('c', pf);
fputc('d', pf);
fclose(pf);
pf = NULL;
return 0;
}
请在文件中输入26个英文字母。
#include<stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
char ch = 0;
for (ch='a'; ch <= 'z'; ch++)
fputc(ch, pf);
fclose(pf);
pf = NULL;
return 0;
}
//换行
#include<stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
char ch = 0;
for (ch = 'a'; ch <= 'z'; ch++)
{
if (ch % 5 == 0)
fputc('\n', pf);//文件流
fputc(ch, pf);
}
//a-97
//b-98
//c-99
//100换行了
fclose(pf);
pf = NULL;
return 0;
}
fgets
fgets - C++ Reference (cplusplus.com)
从流中获取字符串从流中读取字符并将其作为 C 字符串存储到 str 中,直到读取 (num-1) 个字符或到达换行符或文件末尾,以先发生者为准。
换行符使 fgets 停止读取,但它被函数视为有效字符,并包含在复制到 str 的字符串中。
终止空字符会自动附加到复制到 str 的字符之后
- fgets是从文本文件stream读取输出字符串num 到 str的函数
- 头文件#include<stdio.h>
- 参数str是字符指针,指向一个字符数组的指针
- 参数FILE*stream 是文件指针类型的指针变量 指向了一个文件信息区
- 参数num是要复制到 str 的最大字符数(包括终止空字符)(整型提升)
- 返回值是char*类型
- 成功后,函数返回 str。
- 如果在尝试读取字符时遇到文件末尾,则设置 eof 指示器 (feof)。
- 如果在读取任何字符之前发生这种情况,则返回的指针为空指针(str 的内容保持不变)。
- 如果发生读取错误,则设置错误指示器(ferror),并返回空指针(但str指向的内容可能已更改)。
- 读取停止情况
- 读取到了num-1个字符
- 到达换行符\n
- 到达文件末尾
只会读num-1个字符
#include<stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
char str[10] = { 0 };
int ret=fgets(str,7,pf);//实际上只会读6个字符
if (ret == EOF)
{
perror("fgets");
}
else
printf("%s", str);
fclose(pf);
pf = NULL;
return 0;
}
读到\n停止不读了
#include<stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
char str[100] = { 0 };
int ret=fgets(str,12,pf);//实际上只会读6个字符
if (ret == EOF)
{
perror("fgets");
}
else
printf("%s", str);
fclose(pf);
pf = NULL;
return 0;
}
fputs
fputs - C++ Reference (cplusplus.com)
- fputs是将str里的字符输出到文本文件stream
- 头文件#include<stdio.h>
- 参数FILE*stream 是文件指针类型的指针变量 指向了一个文件信息区
- 参数str 是字符指针 指向存放字符串的数组(由const修饰,防止被修改)
- 返回值是int类型
- 成功时,将返回非负值。
- 出错时,该函数返回 EOF 并设置错误指示器(ferror)
#include<stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
char str[] = "abcdef";
fputs(str,pf);
fputs("abcdef", pf);
//两种写法
fclose(pf);
pf = NULL;
return 0;
}
下面两个函数用结构体去举例子 fscanf是输入 fpirntf是输出,先看下对比。
你发现了什么??
- scanf------->键盘-------->读取到程序中 fscanf-------->文件-------->读取到程序中
- printf-------->程序中的数据-------->输入到屏幕上 fprintf-------->程序中的数据------>输入到文件
fscanf
fscanf - C++ Reference (cplusplus.com)
- fscanf是从文件读取数据
- 头文件#include<stdio.h>
- 参数FILE*stream 是文件指针类型的指针变量 指向了一个文件信息区
- 其他和scanf是一样的,不用关心
- 返回值是int类型
#include<stdio.h>
struct S
{
char c;
int i;
float a;
};
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//输入
//struct S s = { 't',7,3.14 };
//fprintf(pf,"%c %d %f",s.c,s.i,s.a);
//格式必须一摸一样
//输出
struct S s = {0};
fscanf(pf, "%c %d %f", &(s.c), &(s.i), &(s.a));
printf("%c %d %f", s.c, s.i, s.a);
fclose(pf);
pf = NULL;
return 0;
}
fprintf
fprintf - C++ Reference (cplusplus.com)
- fprintf是输入数据到文本文件
- 头文件#include<stdio.h>
- 参数FILE*stream 是文件指针类型的指针变量 指向了一个文件信息区
- 其他和printf是一样的,不用关心
- 返回值是int类型
- 成功后,将返回写入的字符总数。
- 如果发生写入错误,则设置错误指示器(ferror)并返回负数。
- 如果在写入宽字符时发生多字节字符编码错误,errno 将设置为 EILSEQ 并返回负数。
#include<stdio.h>
struct S
{
char c;
int i;
float a;
};
int main()
{
FILE* pf = fopen("data.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
struct S s = { 't',7,3.14 };
fprintf(pf,"%c %d %f",s.c,s.i,s.a);
fclose(pf);
pf = NULL;
return 0;
}
前面的函数都是针对于文本文件的,下面这组函数针对的是二进制文件。
fread
fread - C++ Reference (cplusplus.com)
从流中读取数据块从流中读取计数元素数组,每个元素的大小为字节,并将它们存储在 ptr 指定的内存块中。
流的位置指示器按读取的总字节数前进。
如果成功,则读取的总字节数为(大小*计数)。
- fread是向二进制文件读取数据
- 头文件#include<stdio.h>
- 参数FILE*stream 是文件指针类型的指针变量 指向了一个文件信息区
- size_t size是每个元素的大小(以字节为单位)
- size_t count是数组元素的个数
- 参数void *ptr指向大小至少为 (size*count) 字节的内存块的指针(const修饰防止修改,void*类型的指针是因为不知道读取的是哪种类型的指针,void*不能被解引用操作,可以强制转换)
- 返回值是size_t类型
- 返回成功读取的元素总数。
- 如果此数字与 count 参数不同,则表示读取时发生读取错误或到达文件末尾。在这两种情况下,都会设置正确的指标,可以分别用 ferror 和 feof 进行检查。
- 如果大小或计数为零,则该函数返回零,并且流状态和 ptr 指向的内容保持不变。
size_t 是无符号整数类型。
#include<stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int arr[20] = { 0};//10个整型40个字节
fread(arr, 4, 10, pf);
int i = 0;
for (i = 0; i < 10;i++)
{
printf("%d ", arr[i]);
}
fclose(pf);
pf = NULL;
return 0;
}
fwrite
fwrite - C++ Reference (cplusplus.com)
写入要流式传输的数据块将计数元素数组(每个元素的大小为字节)从 ptr 指向的内存块写入流中的当前位置。
流的位置指示器按写入的总字节数前进。
在内部,该函数解释所指向的块,就好像它是一个类型的元素数组,并按顺序写入它们,就好像为每个字节调用一样。
- fwrite是向二进制文件写输入数据的
- 头文件#include<stdio.h>
- 参数FILE*stream 是文件指针类型的指针变量 指向了一个文件信息区
- 参数void *ptr是指向写入元素数组的的指针变量(const修饰防止修改,void*类型的指针是因为不知道输入的输入是哪种类型的指针,void*不能被解引用操作,可以强制转换)
- size_t size是每个元素的大小(以字节为单位)
- size_t count是数组元素的个数
- 返回值size_t类型
- 返回成功写入的元素总数。
- 如果此数字与 count 参数不同,则写入错误阻止函数完成。在这种情况下,将为流设置错误指示器(ferror)。
- 如果大小或计数为零,则该函数返回零,错误指示器保持不变。
size_t 是无符号整数类型。
#include<stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };//10个整型40个字节
fwrite(arr, 4, 10, pf);
fclose(pf);
pf = NULL;
return 0;
}
文件的随机读写
文件结束的判定
✔✔✔✔✔最后,感谢大家的阅读,若有错误和不足,欢迎指正!
希望大家继续坚持在每天敲代码的路上。其实,没有人会一直带着你往前走,你自己一定要成为自己的救赎。
代码---------→【唐棣棣 (TSQXG) - Gitee.com】
联系---------→【邮箱:2784139418@qq.com】