1.为什么要使用文件?
文件,顾名思义就是存储我们所写在电脑上的文本内容。如果没有⽂件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失 了,等再次运⾏程序,是看不到上次程序的数据的,如果要将数据进⾏持久化的保存,我们可以使⽤⽂件
2.什么是文件?
3.流和标准流
4.文件指针
每个被使⽤的⽂件都在内存中开辟了⼀个相应的⽂件信息区,⽤来存放⽂件的相关信息(如⽂件的名 字,⽂件状态及⽂件当前的位置等)。这些信息是保存在⼀个结构体变量中的。该结构体类型是由系统声明的,取名 FILE. 具体的可以看以下解释
VS2013 编译环境提供的 stdio.h 头⽂件中有以下的⽂件类型(FILE)的声明:
struct _ iobuf{char *_ptr;int _cnt;char *_base;int _flag;int _file;int _charbuf;int _bufsiz;char *_tmpfname;};typedef struct _ iobuf FILE ;//对 struct _ iobuf 重命名为 FILE//不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。
FILE* pf; // ⽂件指针变量//使pf指向某个⽂件的⽂件信息区(是⼀个结构体变量), 通过⽂件指针变量能够间接找到与它关联的⽂件。可以看下图所示:
5.文件的打开方式
#include <stdio.h>
//在txt文件里写入字符串
int main()
{
FILE* pr = fopen(".\\test.txt", "w");
if (pr == NULL)
{
perror("fopen");
return 1;
}
//写文件
fputs("Hello!\n", pr);
fputs("I am a boy.", pr);
//关闭文件
fclose(pr);
pr = NULL;
return 0;
}
6.文件的顺序读写函数介绍
fgetc:读取文件中单个字符,可以换行读取,用于“r” :
int fgetc ( FILE * stream );
fputc:将字符串中单个字符,写到文件中,每次只能写一个,可以hun'H'n,用于“w” :
int fputc ( int character, FILE * stream );
fgets:读取文件中字符串,写在数组中,不可以换行读取,用于“r” :
char * fgets ( char * str, int num, FILE * stream );
fputs:将字符串,写在文件中,用于“w” :
int fputs ( const char * str, FILE * stream );
fscanf:格式化输入函数,从文件中读取信息,存放到结构体的各个成员中,用于“r”
int fscanf ( FILE * stream, const char * format, ... );
fprintf:格式化输出函数,把结构体的信息写在文件里,用于“w”
int fprintf ( FILE * stream, const char * format, ... );
fread:读取二进制文件中的信息放在结构体中,用于"rb":
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
fwrite:以二进制形式写在文件中,用于"wb":
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
对应的代码看10.代码附录
7.⽂件的随机读写函数介绍
fseek : 根据⽂件指针的位置和偏移量来定位⽂件指针,来读取文件中的内容。int fseek ( FILE * stream, long int offset, int origin );fseek的第三个参数(int origin)有三种模式:
SEEK_SET 文件开头 SEEK_CUR 文件指针的当前位置 SEEK_END 文件末尾 ftell :返回⽂件指针相对于起始位置的偏移量long int ftell ( FILE * stream );rewind:让⽂件指针的位置回到⽂件的起始位置void rewind ( FILE * stream );对应的代码看 10.代码附录
8.文件读取结束的判定
feof:在⽂件读取过程中,不能⽤feof函数的返回值直接来判断⽂件的是否结束。当⽂件读取结束的时候,判断是读取结束的原因是否是:遇到⽂件尾结束。
int feof ( FILE * stream );
在vs2022中feof遇到结束标志EOF/NULL返回1,没遇到返回0,但是如果文件为空文件的话,则返回0,这也是文件末尾,就不能及时检测。
ferror:判断文件读取过程中是否出现错误,与feof返回值相反 读取完毕 返回0 未读取完,返回1。
int ferror ( FILE * stream );
对应的代码看10.代码附录
9.文件缓冲区
ANSIC 标准采⽤“缓冲⽂件系统” 处理的数据⽂件的,所谓缓冲⽂件系统是指系统⾃动地在内存中为 ,程序中每⼀个正在使⽤的⽂件开辟⼀块“⽂件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓 冲区,装满缓冲区后才⼀起送到磁盘上。如果从磁盘向计算机读⼊数据,则从磁盘⽂件中读取数据输 ⼊到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。
10.代码附录
//1.在txt文件里写入字符串
int main()
{
FILE* pr = fopen(".\\test.txt", "w");
if (pr == NULL)
{
perror("fopen");
return 1;
}
//写文件
fputs("Hello!\n", pr);
fputs("I am a boy.", pr);
//关闭文件
fclose(pr);
pr = NULL;
return 0;
}
//2.从txt文件里读字符串
int main()
{
FILE* pr = fopen(".\\test.txt", "r");
if (pr == NULL)
{
perror("fopen");
return 1;
}
char str[20] = "xxxxxxxxx";
//读文件
fgets(str, 6, pr);
printf("%s", str);
//关闭文件
fclose(pr);
pr = NULL;
return 0;
}
3.从键盘上读字符串 写在屏幕上
int main()
{
char str[20] = "xxxxxxxxx";
fgets(str, 20, stdin);//从键盘(标准输入流stdin)上读取字符串 //文本行输入函数
fputs(str, stdout);将字符串写在屏幕(标准输出流stdout)上 //文本行输出函数
return 0;
}
//4.把结构体的信息写在文件里
struct S
{
char name[20];
int age;
float store;
};
int main()
{
FILE* pr = fopen("test.txt", "w");
if (pr == NULL)
{
perror("fopen");
return 1;
}
struct S s = { "zhangsan",20,88.2f };
//写文件
fprintf(pr,"%s %d %.1f",s.name,s.age,s.store);//格式化输出函数
printf("%s %d %.1f", s.name, s.age, s.store);
//关闭文件
fclose(pr);
pr = NULL;
return 0;
}
//5.从文件中读取信息,存放到结构体的各个成员中
struct S
{
char name[20];
int age;
float score;
};
int main()
{
//打开文件
FILE* pr = fopen("test.txt", "r");
if (pr == NULL)
{
perror("fopen");
return 1;
}
struct S s = {0};
//读文件
fscanf(pr, "%s %d %f", s.name, &(s.age), &(s.score));
//打印到屏幕上
//printf("%s %d %.1f", s.name, s.age, s.score);
fprintf(stdout,"%s %d %.1f", s.name, s.age, s.score);
//关闭文件
fclose(pr);
pr = NULL;
return 0;
}
//6.非文件操作函数 sscanf sprintf
struct S
{
char name[20];
int age;
float score;
};
int main()
{
char arr[100] = { 0 };
struct S s = { "zhangnan",20,88.2f };
sprintf(arr, "%s %d %.1f", s.name, s.age, s.score);//将结构体s中的各个成员数据转化为字符串存放在arr中
printf("%s\n", arr);
struct S t = {0};//创建结构体变量 t
sscanf(arr, "%s %d %f", t.name, &(t.age), &(t.score));//将arr中的数据 提取为格式化数据 存放在结构体 t 中
printf("%s %d %.1f", t.name, t.age, t.score);
return 0;
}
//7.以二进制形式写在文件中
struct S
{
char name[20];
int age;
float store;
};
int main()
{
//打开文件
FILE* pr = fopen("test.txt", "wb");
if (pr == NULL)
{
perror("fopen");
return 1;
}
struct S s = { "zhangsan",30,88.5f };
//写文件
fwrite(&s,sizeof(struct S),1,pr);//以二进制形式写在文件中
printf("%s %d %.1f", s.name, s.age, s.store);
//关闭文件
fclose(pr);
pr = NULL;
return 0;
}
//8.读取二进制的信息写在文件中
struct S
{
char name[20];
int age;
float store;
};
int main()
{
//打开文件
struct S w = {0};
FILE* pr = fopen("test.txt", "rb");
if (pr == NULL)
{
perror("fopen");
return 1;
}
//读文件
printf("%s %d %.1f\n", w.name, w.age, w.store);
fread(&w, sizeof(struct S), 1, pr);//读取二进制文件中的信息写在结构体中
Sleep(1000);//延迟1s
printf("%s %d %.1f", w.name, w.age, w.store);
//关闭文件
fclose(pr);
pr = NULL;
return 0;
}
//9.文件的随机读写
int main()
{
//打开文件
FILE* pr = fopen("test.txt", "r");
if (pr == NULL)
{
perror("fopen");
return 1;
}
//读文件
int ch = 0;
ch = fgetc(pr);
printf("%c\n", ch);//a
ch = fgetc(pr);
printf("%c\n", ch);//b
//定位指针文件
//fseek(pr, 4, SEEK_SET);//(文件开头)相对于起始位置的偏移量
//ch = fgetc(pr);
//printf("%c\n", ch);//e
//fseek(pr, 2, SEEK_CUR);//(文件指针的当前位置)相对于当前位置的偏移量
//ch = fgetc(pr);
//printf("%c\n", ch);//e
fseek(pr, -2, SEEK_END);//(文件末尾位置)相对于当前位置的偏移量
ch = fgetc(pr);
printf("%c\n", ch);//e
printf("%d\n", ftell(pr));//输出文件指针相较于文件的起始位置的偏移量 abcdef
rewind(pr);//将文件指针重新定位到文件的起始位置
ch = fgetc(pr);
printf("%c\n", ch);
//关闭文件
fclose(pr);
pr = NULL;
return 0;
}
//10.拷贝文件将test.txt内容拷贝到 test1.txt
int main()
{
//打开文件
FILE* pr = fopen("test.txt", "r");
if (pr == NULL)
{
perror("fopen\n");
return 1;
}
FILE* pr1 = fopen("test1.txt", "w");
if (pr == NULL)
{
perror("fopen");
fclose(pr);
pr = NULL;
return 1;
}
//拷贝文件开始
int ch = 0;
while ((ch = fgetc(pr)) != EOF)
{
fputc(ch, pr1);
}//拷贝结束
printf("拷贝结束\n");
//关闭文件
fclose(pr);
pr = NULL;
fclose(pr1);
pr1 = NULL;
return 0;
}
//11.文件读取结束判断函数(feof 读取完毕 返回1 、未读取完 返回0)
int main()
{
打开文件
FILE* pr = fopen("test.txt", "r");
if (pr == NULL)
{
perror("fopen\n");
return 1;
}
int ch = 0;
ch = fgetc(pr);
printf("%d\n", feof(pr)); //未读取完 返回0
while ((ch = fgetc(pr)) != EOF)
{
printf("%c\n",ch);
printf("%d\n", feof(pr));//未读取完 返回0
}
printf("===================================\n");
printf("%d\n", feof(pr)); //读取完毕 返回1
判断是什么造成的文件读取结束
if (feof(pr)) //读取完毕 返回1 未读取完 返回0
{
printf("feof:文件内容读取完\n");
return 1;
}
else if (ferror(pr)) //与feof返回值相反 读取完毕 返回0 未读取完 返回1
{
printf("ferror:文件读取过程中出现错误\n");
return -1;
}
关闭文件
fclose(pr);
pr = NULL;
return 0;
}
//12.文件缓冲区(文件拷贝查看缓冲区现象)
int main()
{
FILE* p = fopen("test.txt", "w");
fputs("abcdef", p);//将字符串 abcdef. 写入 p→test.txt
printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
Sleep(10000);
printf("刷新缓冲区\n");
fflush(p);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
//注:fflush 在高版本的VS上不能使用了
printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
Sleep(10000);
fclose(p);//注:fclose在关闭文件的时候,也会刷新缓冲区
p = NULL;
return 0;
}