目录
什么是文件
在计算机科学中,文件是一个存储在磁盘或其他存储设备中的数据集合。文件可以包含各种类型的数据,如文本、图像、音频、视频等。文件通常与程序中的输入输出操作相关联,用于存储和检索数据。
👁️🗨️程序文件
Windows系统上常见的.exe
后缀的文件就是程序文件中的一种
以及C语言中的后缀为.c
的源程序文件,目标文件(windows环境后缀为.obj
)
-
程序文件指的是一种计算机程序的存储形式,通常是以文件的形式保存在计算机的硬盘、固态硬盘、光盘等存储介质中。
-
这些文件包含了可以告诉计算机要执行的操作的一系列指令。它们可以是各种类型的应用程序,例如文本编辑器、图形处理软件、数据库管理系统等。这些应用程序可以在计算机上运行,并提供特定的功能和服务。
-
当用户启动程序文件时,计算机会读取文件中的指令,将其加载到内存中,并按照指令的顺序执行。程序文件中的代码可以执行各种操作,例如读取和写入文件、连接到网络、调用其他程序等。
-
简单说,程序文件就是一种计算机程序的存储形式,包含了可以告诉计算机要执行的操作的一系列指令。
👁️🗨️数据文件
在C语言中,数据文件是由字节组成的序列,可以存储在硬盘或其他存储介质中。C语言使用文件I/O函数包括fopen、fclose、fread、fwrite、fprintf、fscanf等。
来读取和写入数据文件。
数据文件是一种用于存储数据的文件,其中数据可以是以文本形式或二进制形式存储的。
👁️🗨️文件名
- 文件名是对文件的标识符,用于在操作系统中唯一地标识一个文件。
- 文件名包含3部分:文件路径+文件名主干+文件后缀
例如:c:\code\test.txt
为了方便起见,文件标识常被称为文件名。
文件的打开与关闭
👁️🗨️文件指针FILE
在计算机编程中,文件指针是一种用于跟踪和管理文件位置的机制。
当我们打开一个文件,被打开的文件就维护了一个文件信息区。这个信息区是一个特殊数据结构体,这个数据结构包含了文件的名称、在磁盘上的位置、当前读/写位置以及其他一些信息。
而文件指针可以作为一个跳板,通过这个指针,我们可以找到并操作存储特定文件信息的结构。
例如,VS2013编译环境提供的 stdio.h 头文件中有以下的文件类型申明:
struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;
不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。
每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,
使用者不必关心细节。
一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。
FILE* pf;//创建文件指针变量
👁️🗨️打开关闭文件
在C语言中,我们使用标准库函数来打开和关闭文件,它在<stdio.h>
头文件中定义。
- 使用
fopen()
函数来打开文件。
FILE *fopen(const char *filename, const char *mode);
该函数接受两个参数:文件名和打开模式。这个函数返回一个 FILE 指针,如果打开文件失败,那么将返回 NULL。
- 使用
fclose()
函数来关闭文件。
int fclose(FILE *stream);
这里的stream参数是你希望关闭的文件的文件指针。
注意:
1.fclose()
不会把指针置空,需主动置空。
2.如果文件成功关闭,fclose会返回0
。如果发生错误,它会返回EOF
。因此,你可以检查fclose的返回值以确保文件已成功关闭。
所有打开模式:
用 法 | 模 式 | 注 意 事 项 |
---|---|---|
"r" | 以只读方式打开文件 | 文件指针会放在文件的开头。如果文件不存在,返回NULL。 |
"w" | 以只写方式打开文件 | 如果文件不存在则创建一个新文件进行写入,如果文件存在则清空原有内容。文件指针会放在文件的开头。 |
"a" | 以追加方式打开文件 | 如果文件不存在则创建一个新文件进行写入,如果文件存在则在文件末尾追加内容。文件指针会放在文件的末尾。 |
"rb" | 以只读方式打开二进制文件 | 文件指针会放在文件的开头。 |
"wb" | 以只写方式打开二进制文件 | 如果文件不存在则创建一个新文件进行写入,如果文件存在则清空原有内容。文件指针会放在文件的开头。 |
"ab" | 以追加方式打开二进制文件 | 如果文件不存在则创建一个新文件进行写入,如果文件存在则在文件末尾写入。文件指针会放在文件的末尾。 |
"r+" | 以读写方式打开文件 | 文件指针会放在文件的开头。如果文件不存在,返回NULL。 |
"w+" | 以读写方式打开文件 | 如果文件不存在则创建一个新文件进行读写,如果文件存在则清空原有内容从头开始读写。文件指针会放在文件的开头。 |
"a+" | 以读写方式打开文件 | 如果文件不存在则创建一个新文件进行读写,如果文件存在则在已有内容后追加新的内容。文件指针会放在文件的末尾。 |
"rb+" | 以读写方式打开二进制文件 | 文件指针会放在文件的开头。如果文件不存在,返回NULL。 |
"wb+" | 以读写方式打开二进制文件 | 如果文件不存在则创建一个新文件进行读写,如果文件存在则清空原有内容从头开始读写。文件指针会放在文件的开头。 |
"ab+" | 以读写方式打开二进制文件 | 如果文件不存在则创建一个新文件进行读写,如果文件存在则在已有内容后追加新的内容。文件指针会放在文件的末尾。 |
这个表格详细列出了fopen函数的模式及其对应的描述。每种模式都有其特定的用途和效果,需要根据实际需求来选择合适的模式。
顺序读写函数介绍
功能 | 函数名 | 适用于 |
---|---|---|
字符输入函数 | fgetc | 所有输入流 |
字符输出函数 | fputc | 所有输出流 |
文本行输入函数 | fgets | 所有输入流 |
文本行输出函数 | fputs | 所有输出流 |
格式化输入函数 | fscanf | 所有输入流 |
格式化输出函数 | fprintf | 所有输出流 |
二进制输入 | fread | 文件 |
二进制输出 | fwrite | 文件 |
👁️🗨️字符输入输出
结合上面知识
例如
输出单个字符
#include <stdio.h>
int main()
{
//创建文件指针
FILE* pf = fopen("data.txt", "w");
if (pf == NULL)
{
//文件打开失败
perror("fopen:");
return 1;
}
//将字符c输出到文件流中,程序会在源文件目录中寻找data.txt文件,如果没有将创建,并写入一个字符'c'
fputc('c', pf);
//将字符c输出到标准输入流,一般是在屏幕上输出
fputc('c', stdout);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
顺序读取字符:
int main()
{
FILE* pf = fopen("data.txt", "r");//目录下存有该文件
/*先省略了错误判断*/
int ch = fgetc(pf);
printf((char*)&ch);//输出a
ch = fgetc(pf);
printf((char*)&ch);//输出b
ch = fgetc(pf);
printf((char*)&ch);//输出c
ch = fgetc(pf);
printf((char*)&ch);//输出d
fclose(pf);
pf = NULL;
return 0;
}
👁️🗨️文本行(输入/输出)
写入一行/多行数据:
//写入一行/多行数据
int main()
{
FILE* pf = fopen("data.txt", "w");
//省略了错误判断
fputs("hello world", pf);//未输入换行符
fputs("hello\n", pf);//输入换行符
fputs("haha\n", pf);
fclose(pf);
pf = NULL;
return 0;
}
文件就在这里搁着,再kan一下读取固定长度的数据:
//读取一行数据
int main()
{
FILE* pf = fopen("data.txt", "r");
//省略了错误判断
char arr[30] = { 0 };
fgets(arr, 10, pf);//实际读取10-1个字符
printf("%s\n", arr);
fgets(arr, 10, pf);
printf("%s\n", arr);
fgets(arr, 10, pf);
printf("%s\n", arr);
fclose(pf);
pf = NULL;
return 0;
}
第二次调用printf
函数时之所以会换行两次,是因为第二次调用fgets
后arr
中已经存放了一个'\n'
,而printf函数中也存在一个'\n'
,所以会换行两次.
👁️🗨️格式化数据(i/o)
就是带有格式的数据,如结构体
将结构体写入到文件中:
typedef struct
{
char name[10];
int age;
int score;
}stu;
int main()
{
//创建并初始化结构体
stu s1 = {"wly", 23, 666 };
//创建文件指针并检查返回值
FILE* pf = fopen("wly.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//将结构体中格式化的数据输出到磁盘文件里
fprintf(pf, "%s %d %d", s1.name, s1.age, s1.score);
//关闭文件,并将文件指针置空。
fclose(pf);
pf = NULL;
return 0;
}
再从文件中读取结构体数据
int main()
{
//创建一个空的结构体
stu s2 = {0};
//创建文件指针并检查返回值
FILE* pf = fopen("wly.txt", "r");//读取文本
if (pf == NULL)
{
perror("fopen");
return 1;
}
//从文件中抓取数据到程序的结构体中
fscanf(pf, "%s %d %d", s2.name, &s2.age, &s2.score);
//关闭文件,并将文件指针置空。
fclose(pf);
pf = NULL;
return 0;
}
👁️🗨️二进制读写
fwrite
和fread
是C语言中用于二进制文件输入和输出的函数,它们允许你以二进制形式读取和写入数据。这些函数通常用于处理二进制文件,如图像、音频、数据库文件等,而不是文本文件。下面分别解释它们的用途和用法:
- fwrite 函数(File Write):
- fwrite函数用于将二进制数据从内存写入到文件。其原型如下:
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
- ptr:指向要写入文件的数据块的指针。
- size:每个元素的大小(以字节为单位)。
- count:要写入的元素的数量。
- stream:指向要写入数据的文件流。
栗子,将整个数组写入到二进制文件中:
int main()
{
int data[] = { 1,2,3,4,5 };
FILE* pf = fopen("data.txt", "wb");// 打开文件以二进制写入模式
if (pf != NULL)
{
fwrite(data, sizeof(int), 5, pf);// 写入整数数组到文件
fclose(pf);
pf = NULL;
}
return 0;
}
- fread 函数(File Read):
- fread函数用于从文件中读取二进制数据到内存中。其原型如下:
size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
- ptr:指向存储读取数据的内存块的指针。
- size:每个元素的大小(以字节为单位)。
- count:要读取的元素的数量。
- stream:指向要读取数据的文件流。
栗子,从二进制文件中,读取一个数组:
int main()
{
int data[5] = { 0};
FILE* pf = fopen("data.txt", "rb");// 打开文件以二进制读取模式
if (pf != NULL)
{
fread(data, sizeof(int), 5, pf);// 从文件中读取整数数组
fclose(pf);
pf = NULL;
}
return 0;
}
可以看到,data数组中已经获得了磁盘文件的数据
这些函数对于处理二进制数据非常有用,但需要注意文件的打开模式(例如,"wb"用于写入二进制文件,"rb"用于读取二进制文件),以及数据的大小和数量的正确配置。此外,它们不会自动处理数据的格式,所以你需要确保读取和写入数据的方式与数据的格式一致。
再举个栗子
以二进制形式读写结构体数组:
//二进制读写结构体数组
//定义结构体
typedef struct
{
char name[10];//人名
int age;//年龄
}stu;
//主函数
int main()
{
//创建一个包含3个stu结构体的数组
stu s1[3] = { { "zhangsan", 20 } , { "lisi", 21 } , { "wangwu", 22 } };
//将结构体以二进制形式写入文件
FILE* pf = fopen("data.txt", "wb");
if (pf != NULL)
{
//使用fwrite函数写入数据
fwrite(s1, sizeof(stu), 3, pf);
fclose(pf);
pf = NULL;
}
else
{
perror("fopenwb:");
return 1;
}
//从二进制文件中读取结构体数组
stu s2[3] = { 0 };
pf = fopen("data.txt", "rb");
if (pf != NULL)
{
//使用fread函数从二进制文件抓取数据到程序中
fread(s2, sizeof(stu), 3, pf);
fclose(pf);
pf = NULL;
}
else
{
perror("fopenrb:");
return 1;
}
return 0;
}
程序运行起来后,看到目录下data.txt文件中出现了数据,其中某些数据我们是看不懂的
程序运行完fread函数后,可以看到原本为空的s2数组中出现了从文件中抓取的数据。
👻fprintf fscanf 和 printf scanf 的区别
printf函数主要用于将信息输出到控制台,而fprintf函数则主要用于将信息输出到文件或其他输出设备。
scanf函数适用于从键盘输入数据,而fscanf函数适用于从文件中读取数据。
👻sscanf 与 sprintf
1.sprintf函数:
- sprintf函数用于将格式化的数据写入一个字符串中,而不是打印到标准输出或文件。它的原型如下:
int sprintf(char *str, const char *format, ...);
- str是要解析的输入字符串。
- format是一个字符串,指定了要解析的数据类型和格式。
- 可变数量的参数(使用省略号 …)包含了要解析的数据存储位置。
例如,以下代码将整数和浮点数格式化为字符串:
int main()
{
char buffer[50];
int num = 42;
float f = 3.14;
sprintf(buffer, "Integer: %d, Float: %.2f", num, f);
printf("Formatted String: %s\n", buffer);
return 0;
}
这将把整数和浮点数格式化为字符串,并将结果存储在buffer中,然后打印出来。
输出结果:
Formatted String: Integer: 42, Float: 3.14
- sscanf函数:
- sscanf函数用于从一个字符串中按照指定的格式读取数据,并将其存储到变量中。它的原型如下:
int sscanf(const char *str, const char *format, ...);
- str是要解析的输入字符串。
- format是一个字符串,指定了要解析的数据类型和格式。
- 可变数量的参数(使用省略号 …)包含了要解析的数据存储位置。
例如,以下代码从字符串中解析整数和浮点数:
char input[] = "Integer: 42, Float: 3.14";
int num;
float f;
sscanf(input, "Integer: %d, Float: %f", &num, &f);
printf("Parsed Integer: %d, Parsed Float: %.2f\n", num, f);
这将从字符串input中解析整数和浮点数,并将结果存储在num和f中,然后打印出来。
总之,sprintf用于将格式化的数据写入字符串,而sscanf用于从字符串中解析数据并存储到变量中。它们在处理字符串时非常有用,特别是在处理文件输入/输出或网络通信时。但要小心使用它们,以避免缓冲区溢出和安全漏洞。
👻输入流和输出流的概念
在C语言中,输入和输出都通过流(stream)的概念来进行处理。流是一个抽象的概念,它代表着数据的序列,可以是字符、数字或者其他类型的数据。C语言中提供了标准的输入和输出流,分别对应着标准输入设备(通常是键盘)和标准输出设备(通常是屏幕)。
输入流(Input Stream):
输入流是数据从外部输入到程序中的流。在C语言中,输入流通常关联着键盘或者文件。常见的输入函数有scanf和fscanf,它们从输入流中读取数据并存储到变量中。
- scanf函数:从标准输入(键盘)读取数据。
int num;
printf("Enter a number: ");
scanf("%d", &num);
- fscanf函数:从文件中读取数据。
FILE *file = fopen("example.txt", "r");
int num;
fscanf(file, "%d", &num);
fclose(file);
输出流(Output Stream):
输出流是数据从程序输出到外部的流。在C语言中,输出流通常关联着屏幕或者文件。常见的输出函数有printf和fprintf,它们将数据格式化并输出到输出流中。
- printf函数:向标准输出(屏幕)打印数据。
int num = 42;
printf("The number is: %d", num);
- fprintf函数:将数据输出到文件中。
FILE *file = fopen("output.txt", "w");
int num = 42;
fprintf(file, "The number is: %d", num);
fclose(file);
流的概念使得输入和输出在不同的环境下(例如,键盘、文件、网络等)具有统一的处理方式,这样程序不需要关心数据的具体来源或去向,只需要使用适当的输入和输出函数即可。这种抽象的设计提高了程序的灵活性和可移植性。
随机读写函数
🪄fseek函数
fseek 函数是C标准库提供的文件操作函数之一,它用于在文件中设置文件指针的位置,以便进行随机读写访问文件。 fseek 允许你在文件中移动指针到指定的位置,以便读取或写入数据。这对于处理大型文件或需要在文件中执行跳转的情况非常有用。
有了fseek,便可把文件看做是数组,在fopen()打开的文件中直接移动到任意字节处。
fseek 函数的原型如下:
int fseek(FILE* stream, long int offset, int origin);
- stream :指向要设置文件指针位置的文件流的指针。
- offset :要移动的字节数,正数表示向文件末尾移动,负数表示向文件开头移动。
- origin :指定偏移量的起始位置,可以是以下常量之一:
- SEEK_SET:从文件的开头开始计算偏移量。
- SEEK_CUR:从当前文件指针的位置开始计算偏移量。
- SEEK_END:从文件的末尾开始计算偏移量。
fseek 返回值是一个整数,通常用于检查是否移动成功。如果成功,返回值为0;如果出错,返回值非零。
以下是一些示例用法:
- 从文件开头移动到指定位置:
FILE *file = fopen("example.txt", "r");
if (file != NULL) {
fseek(file, 20, SEEK_SET); // 从文件开头移动到第 20 个字节处
// 现在可以在这个位置读取文件的内容
fclose(file);
}
- 从当前位置向前或向后移动:
FILE *file = fopen("example.txt", "r");
if (file != NULL) {
fseek(file, 10, SEEK_CUR); // 从当前位置向前移动 10 个字节
// 现在可以在这个位置读取文件的内容
fclose(file);
}
- 从文件末尾向前移动:
FILE *file = fopen("example.txt", "r");
if (file != NULL) {
fseek(file, -30, SEEK_END); // 从文件末尾向前移动 30 个字节
// 现在可以在这个位置读取文件的内容
fclose(file);
}
fseek 函数使文件指针在文件中移动,以便在需要时可以读取或写入数据。它对于在文件中进行随机访问非常有用。请注意,在使用 fseek 之前,要确保成功打开文件(通过 fopen 函数),并且文件模式允许读取或写入,具体取决于你的需求
🪄ftell函数
返回文件指针相对于起始位置的偏移量
ftell 函数是C标准库提供的文件操作函数之一,它用于获取当前文件指针在文件中的位置(偏移量)。ftell 返回的是一个 long int 类型的值,表示文件指针相对于文件开头的字节偏移量。
ftell 函数的原型如下:
long int ftell(FILE *stream);
- stream:指向文件流的指针,它是你要获取当前位置的文件。
- ftell 函数返回当前文件指针的位置。通常情况下,它返回非负整数,表示文件指针距离文件开头的字节偏移量。如果出现错误,ftell 返回 -1L(一个长整数的特殊值,表示错误)。
🪄rewind函数
让文件指针的位置回到文件的起始位置
void rewind(FILE *stream);
函数没有返回值,它只负责将文件指针移动到文件的开头。
文本文件和二进制文件
文本文件和二进制文件是两种不同类型的文件,它们在存储和表示数据方面有一些重要的区别。下面我将解释这两种文件类型的特点和区别:
文本文件(Text Files):
- 数据表示方式:文本文件以文本形式存储数据,其中数据通常由字符组成,包括字母、数字、标点符号等。这些字符可以是可打印字符(如字母和数字)或不可打印字符(如换行符和制表符)。
- 可读性:文本文件通常是人类可读的,因为它们以文本形式存储数据。你可以使用文本编辑器打开文本文件,并轻松查看和编辑其中的内容。
- 文件大小:由于文本文件以字符为单位存储数据,因此它们可能相对较大。每个字符通常占用一个或多个字节的存储空间,具体取决于字符编码(如ASCII或UTF-8)。
- 示例:文本文件的示例包括.txt文件(文本文档)、.csv文件(逗号分隔值文件)、.html文件(网页源代码)等。
二进制文件(Binary Files):
- 数据表示方式:二进制文件以二进制形式存储数据,其中数据可以包括任意的字节序列,包括文本字符、图像、音频、视频等。
- 可读性:二进制文件通常不是人类可读的,因为它们包含了用于表示各种数据类型的字节序列。需要特定的程序来解释和处理这些数据。
- 文件大小:由于二进制文件可以存储各种数据类型,因此它们的大小可能会更小或更大,具体取决于存储的数据和文件格式。
- 示例:二进制文件的示例包括图像文件(如.jpg和.png)、音频文件(如.mp3和.wav)、可执行文件(如.exe和.dll)等。
在编程和文件处理中,你需要根据需要选择使用文本文件或二进制文件。一些编程语言和库提供了特定于文本或二进制文件的操作函数,以便于处理这两种类型的文件。
总之,文本文件和二进制文件在数据表示、可读性和存储方式方面存在显著差异。了解这些差异对于正确处理文件非常重要。根据你的应用程序需求和文件内容,选择适当的文件类型非常关键。
vs编译器下打开二进制文件
文件读取结束的判定
feof 的作用是:当文件读取结束的时候,判断是读取结束的原因是否是:遇到文件尾结束。
- 文本文件读取是否结束,判断返回值是否为
EOF
( fgetc ),或者NULL
( fgets )
例如:- fgetc 判断是否为
EOF
. - fgets 判断返回值是否为
NULL
.
- fgetc 判断是否为
- 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
例如:- fread判断返回值是否小于实际要读的个数。
使用 fgets 函数:
- fgetc 函数从文件中读取一个字符,并返回读取的字符或 EOF(End of File)。
- 当 fgetc 返回 EOF 时,表示已经到达文件的末尾,不再有可读取的字符。
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "r");
if (file != NULL) {
int ch;
while ((ch = fgetc(file)) != EOF) {
// 处理读取的字符
putchar(ch);
}
fclose(file);
}
return 0;
}
使用 fgets 函数:
- fgets 函数从文件中读取一行文本,并返回读取的字符串或 NULL。
- 当 fgets 返回 NULL 时,表示已经到达文件的末尾,没有更多的文本行可读取。
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "r");
if (file != NULL) {
char line[100];
while (fgets(line, sizeof(line), file) != NULL) {
// 处理读取的文本行
printf("%s", line);
}
fclose(file);
}
return 0;
}
使用 feof 函数:
feof 函数用于检查文件流的结束标志。它返回非零值(true)表示已经到达文件的末尾,否则返回零(false)。
#include <stdio.h>
#include <stdlib.h>
int main()
{
int c; // 注意:int,非char,要求处理EOF
FILE* fp = fopen("test.txt", "r");
if(!fp) {
perror("File opening failed");
return EXIT_FAILURE;
}
//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 <stdio.h>
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))
printf("Error reading test.bin: unexpected end of file\n");
else if (ferror(fp)) {
perror("Error reading test.bin");
}
}
fclose(fp);
}
文件缓冲区
ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。
因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。
如果不做,可能导致读写文件的问题。