✅作者简介:大家好,我是橘橙黄又青,一个想要与大家共同进步的男人
个人主页:橘橙黄又青_C语言,数据结构,函数-CSDN博客
目的:学习文件操作,即文件相关函数的学习
在这里首先放置我个人认为好的学习c语言的网站
:cplusplus.com:https://legacy.cplusplus.com/reference/clibrary/
好了我们现在开始吧?
在以前各章所处理数据的输⼊输出都是以终端为对象的,即从终端的键盘输⼊数据,运⾏结果显⽰到 显⽰器上。其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使⽤,这⾥处 理的就是磁盘上⽂件。
c:\ code \ test . txt
#include
int main()
{
int a = 10000;
FILE* pf = fopen("test.txt", "wb");
fwrite(&a, 4, 1, pf);//⼆进制的形式写到⽂件中
fclose(pf);
pf = NULL;
return 0;
}
在此之前先了解一个抽象的概念:
那为什么我们从键盘输⼊数据,向屏幕上输出数据,并没有打开流呢?
• stdin - 标准输⼊流,在⼤多数的环境中从键盘输⼊,scanf函数就是从标准输⼊流中读取数据。• stdout - 标准输出流,⼤多数的环境中输出⾄显⽰器界⾯,printf函数就是将信息输出到标准输出流中。• stderr - 标准错误流,⼤多数环境中输出到显⽰器界⾯。这是默认打开了这三个流,我们使⽤scanf、printf等函数就可以直接进⾏输⼊输出操作的。
stdin、stdout、stderr 三个流的类型是: FILE* ,通常称为⽂件指针。
struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;
FILE* pf;//⽂件指针变量
//打开⽂件
FILE * fopen ( const char * filename, const char * mode );//两个参数:一个是文件名,一个是文件使用方式
//关闭⽂件
int fclose ( FILE * stream );
⽂件使⽤⽅式
|
含义
|
如果指定⽂件不存在
|
“r”(只读)
|
为了输⼊数据,打开⼀个已经存在的⽂本⽂件
|
出错
|
“w”(只写)
|
为了输出数据,打开⼀个⽂本⽂件
|
建⽴⼀个新的⽂件
|
“a”(追加)
|
向⽂本⽂件尾添加数据
|
建⽴⼀个新的⽂件
|
“rb”(只读)
|
为了输⼊数据,打开⼀个⼆进制⽂件
|
出错
|
“wb”(只写)
|
为了输出数据,打开⼀个⼆进制⽂件
|
建⽴⼀个新的⽂件
|
“ab”(追加)
|
向⼀个⼆进制⽂件尾添加数据
|
建⽴⼀个新的⽂件
|
“r+”(读写)
|
为了读和写,打开⼀个⽂本⽂件
|
出错
|
“w+”(读写)
|
为了读和写,建议⼀个新的⽂件
|
建⽴⼀个新的⽂件
|
“a+”(读写)
|
打开⼀个⽂件,在⽂件尾进⾏读写
|
建⽴⼀个新的⽂件
|
“rb+”(读写)
|
为了读和写打开⼀个⼆进制⽂件
|
出错
|
“wb+”(读
写)
|
为了读和写,新建⼀个新的⼆进制⽂件
|
建⽴⼀个新的⽂件
|
“ab+”(读
写)
|
打开⼀个⼆进制⽂件,在⽂件尾进⾏读和写
|
建⽴⼀个新的⽂
|
我们怎么理解读和写看图:
这里我们演示一下打开关闭,实战代码:
/* fopen fclose example */
#include
int main ()
{
FILE * pFile;
//打开⽂件
pFile = fopen ("myfile.txt","w");
//⽂件操作
if (pFile!=NULL)
{
fputs ("fopen example",pFile);
//关闭⽂件
fclose (pFile);
}
return 0;
}
函数名
|
功能
|
适⽤于
|
fgetc
|
字符输⼊函数
|
所有输出流
|
fputc
|
字符输出函数
|
所有输出流
|
fgets
|
⽂本⾏输⼊函数
|
所有输出流
|
fputs
|
⽂本⾏输出函数
|
所有输出流
|
fscanf
|
格式化输⼊函数
|
所有输出流
|
fprintf
|
格式化输出函数
|
所有输出流
|
fread
|
⼆进制输⼊
|
⽂件
|
fwrite
|
⼆进制输出
|
⽂件
|
那好我们来一个一个介绍:打开网站:
https://legacy.cplusplus.com/reference/clibrary/
参数是:文件名和流
代码实现:
#include
#include
int main()
{
FILE* pf = fopen("data.txt", "w");//写入文件
if (pf == NULL)
{
perror("fopen");
return 1;
}
fputc('a', pf);//写入一个字符'a'
fputc('\n', pf);
fputc('b', pf);
fclose(pf);
return 0;
}
fputc只能一个一个字符的输入,也可以写一个循环输入多个字符。
for (i = 0; i < 26; i++) {
fputc('a' + 1, pf);
fputc('\n', pf);//写完换行
}
现在先我们输入字符进“data.txt”文件中,比如说输入:“abcdefg",然后实现代码读操作
代码:
#include
#include
int main()
{
FILE* pf = fopen("data.txt", "r");//写入文件
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = fgetc(pf);//读取一个字符
printf("%c", ch);//打印
fclose(pf);
pf = NULL;
return 0;
}
具体操作和输出结果如下:
当然也可以写成循环的形式,但是要注意什么时候结束,比如说:
下面代码:
#include
#include
int main()
{
FILE* pf = fopen("data.txt", "r");//写入文件
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = 0;
while ((ch = fgetc(pf)) != ' ') {
printf("%c", ch);//打印
}
fclose(pf);
pf = NULL;
return 0;
}
两种情况:
这就要看文件文本句末了,避免造成死循环。
接下来我们学习一个复制文件内容的操作:
假设文件里面有代码
代码实现:
//从data.txt中读取数据
//写到data2.txt的文件中
#define _CRT_SECURE_NO_WARNINGS
#include
#include
int main()
{
FILE* pfread = fopen("data.txt", "r");//读
if (pfread == NULL)
{
perror("fopen->data1.txt");//报错详细一点
return 1;
}
FILE* pfwrite = fopen("data2.txt", "w");//写
if (pfwrite == NULL)
{
fclose(pfread);//如果出现错误先关闭打开文件
pfread = NULL;
perror("fopen->data2.txt");
return 1;
}
//数据的读写(拷贝)
int ch = 0;
while ((ch = fgetc(pfread)) != EOF)
{
fputc(ch, pfwrite);//把ch写入pfwrite
}
fclose(pfread);
fclose(pfwrite);
return 0;
}
代码实现:
#include
#include
int main()
{
FILE* pf = fopen("data.txt", "w");
if (pf == NULL)
{
return 1;
}
//写文件 - 写一行
fputs("abcdef\n", pf);
fputs("abcdef\n", pf);
fputs("abcdef\n", pf);
fputs("abcdef\n", pf);
fclose(pf);
pf = NULL;
return 0;
}
输出结果:
三个参数:
1. 输入地的指针
2.输入个数,但是要-1因为最后要输入\0
3.流
代码实现:
#include
#include
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
return 1;
}
//读取
char arr[20] = "xxxxxxxxxxxxxxx";
fgets(arr, 10, pf);//从流中读取9个字符(有一个放入\0)放入arr中
fclose(pf);
pf = NULL;
return 0;
}
输出结果:
当然也可以输出到屏幕上:
看代码:
#include
#include
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
return 1;
}
//读取
char arr[20] = "xxxxxxxxxxxxxxx";
fgets(arr, 10, stdin);//标准输入流
fputs(arr, stdout);//标准输出流
fclose(pf);
pf = NULL;
return 0;
}
输出结果:
这里要注意的是输入流和输出流在函数的位置。
fprintf代码实现:
#include
#include
struct Stu
{
char name[20];
int age;
float score;
};
int main()
{
struct Stu s = { "zhangsan", 20, 90.5f };
FILE*pf = fopen("data.txt", "w");
if (pf == NULL)
{
return 1;
}
//写文件
//printf(""%s %d %.1f", s.name, s.age, s.score");//很相似
fprintf(pf, "%s %d %.1f", s.name, s.age, s.score);
//
fclose(pf);
pf = NULL;
return 0;
}
输出结果:
同理:fscanf
假设文件里有:
代码:
#include
#include
struct Stu
{
char name[20];
int age;
float score;
};
int main()
{
struct Stu s = {0};
FILE* pf = fopen("data.txt", "r");//读
if (pf == NULL)
{
return 1;
}
//写读文件
fscanf(pf, "%s %d %f", s.name, &(s.age), &(s.score));
fprintf(stdout, "%s %d %.1f\n", s.name, s.age, s.score);//输出屏幕
//
fclose(pf);
pf = NULL;
return 0;
}
输出结果:
首先我们先来学习一下这个函数:
代码实现:
#include
#include
struct Stu
{
char name[20];
int age;
float score;
};
int main()
{
struct Stu s = {"zhangsan", 20, 90.5};
FILE* pf = fopen("data.txt", "wb");//wb是以二进制的方式写入
if (pf == NULL)
{
return 1;
}
//二进制的形式写文件
fwrite(&s, sizeof(s), 1, pf);
fclose(pf);
pf = NULL;
return 0;
}
输出:
这里是以二进制输入的文本翻译成这样,是因为文本不具备二进制翻译,但是如果以二进制输出是和输入一样的结果,下面我们把刚刚以二进制输入文件以二进制输出看看。
这里我们可以看到,参数和上面的fwite是一样的。
代码实现:
#include
#include
struct Stu
{
char name[20];
int age;
float score;
};
int main()
{
struct Stu s = {0};
FILE* pf = fopen("data.txt", "rb");//rb以二进制形式读进
if (pf == NULL)
{
return 1;
}
//二进制的形式du文件
fread(&s, sizeof(s), 1, pf);
printf("%s %d %lf", s.name , s.age, s.score );
fclose(pf);
pf = NULL;
return 0;
}
输出结果:
在这里我们在认识两个函数sscanf和sprintf.
对比:
使用:
#include
struct S
{
char name[20];
int age;
float score;
};
int main()
{
struct S s = { "zhangsan", 20, 85.5f };
struct S tmp = { 0 };
char arr[100] = { 0 };
sprintf(arr, "%s %d %f", s.name, s.age, s.score);//把结构体s的数据输入arr
printf("%s\n", arr);
//
sscanf(arr, "%s %d %f", tmp.name, &(tmp.age), &(tmp.score));//把arr结构体数据输入tmp
printf("%s %d %f\n", tmp.name, tmp.age, tmp.score);
return 0;
}
这里要慢慢理解,
根据⽂件指针的位置和偏移量来定位⽂件指针。
什么意思,来
返回⽂件指针相对于起始位置的偏移量。
函数内容:
long int ftell ( FILE * stream );
现在我们来实现fseek和ftell
代码展示:
#include
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);//让光标指向d
int n = ftell(pf);//计算相对起始位置的偏移量并保存
printf("%d\n", n);
fclose(pf);
pf = NULL;
return 0;
}
输出结果:
再看看
这个:
#include
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);//让光标指向d
int n = ftell(pf);//计算相对起始位置的偏移量并保存
printf("%d\n", n);
fseek(pf, -4, SEEK_CUR);//当前位置
printf("%c\n", ch);
fclose(pf);
pf = NULL;
return 0;
}
输出结果:
怎么理解:
作用:让⽂件指针的位置回到⽂件的起始位置
代码展示:
#include
//data.txt里面有abcdefg
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);//光标指向c
rewind(pf);//让⽂件指针的位置回到⽂件的起始位置
ch = fgetc(pf);
printf("%c\n", ch);
fclose(pf);
pf = NULL;
return 0;
}
输出结果:
#include
#include
int main(void)
{
int c; // 注意:int,⾮char,要求处理EOF
FILE* fp = fopen("test.txt", "r");
if (!fp) {
perror("File opening failed");
return EXIT_FAILURE;//1
}
//fgetc 当读取失败的时候或者遇到⽂件结束的时候,都会返回EOF
while ((c = fgetc(fp)) != EOF) // 标准C I/O读取⽂件循环
{
putchar(c);
}
//判断是什么原因结束的
if (ferror(fp))//遇到错误结束
puts("I/O error when reading");
else if (feof(fp))//遇到文末结束
puts("End of file reached successfully");
fclose(fp);
}
#include
enum { SIZE = 5 };
int main(void)
{
double a[SIZE] = { 1.,2.,3.,4.,5. };
FILE* fp = fopen("test.bin", "wb"); // 必须⽤⼆进制模式
fwrite(a, sizeof * a, SIZE, fp); // 写 double 的数组
fclose(fp);
double b[SIZE];
fp = fopen("test.bin", "rb");
size_t ret_code = fread(b, sizeof * b, SIZE, fp); // 读 double 的数组
if (ret_code == SIZE) {//判断返回值是否⼩于实际要读的个数
puts("Array read successfully, contents: ");
for (int n = 0; n < SIZE; ++n) printf("%f ", b[n]);
putchar('\n');
}
else { // error handling
if (feof(fp))//yudao文末结束
printf("Error reading test.bin: unexpected end of file\n");
else if (ferror(fp)) {//遇到错误结束
perror("Error reading test.bin");
}
}
fclose(fp);
}
#include
#include
//VS2019 WIN11环境测试
int main()
{
FILE* pf = fopen("test.txt", "w");
fputs("abcdef", pf);//先将代码放在输出缓冲区
printf("睡眠10秒-已经写数据了,打开test.txt⽂件,发现⽂件没有内容\n");
Sleep(10000);
printf("刷新缓冲区\n");
fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到⽂件(磁盘)
//注:fflush 在⾼版本的VS上不能使⽤了
printf("再睡眠10秒-此时,再次打开test.txt⽂件,⽂件有内容了\n");
Sleep(10000);
fclose(pf);
//注:fclose在关闭⽂件的时候,也会刷新缓冲区
pf = NULL;
return 0;
}