在C语言程序设计的过程中一般有两中文件参与,分别是程序文件和数据文件。
程序文件:.c结尾的程序的原文件,这是纯C代码。还有编译产生的可执行程序exe。
数据文件:在程序执行的过程中会需要数据和产生数据,那么这个数据就被存放在一个数据文件中。
我们学习通讯录的时候我们一次输入的人的数据在一次输入之后我们程序结束这个人的数据就消失了我们无法把这些人的数据存放起来进行一个统一的管理,在下一次我们想要使用通讯录的时候我们还需要把这些人的学习进行再一次的输入非常明显这是非常麻烦的。我们想到应该在程序结束之后保存文件信息,下一次打开的时候不需要再一次输入信息。保存应该保存到那里?信息保存应该是非常持久,不会因为除人以外的原因消失,一般的持化方法是将数据存放在硬盘里面或者存放到数据库中。使用文件我们可以把数据存放到电脑中的硬盘上面做到了数据的持久化。
主要包涵了三个部分 文件路径+文件名称+文件后缀名
eg:C:\cound\text.txt C:\cound\ +text .+ txt;
在一个相同的路径下文件名称必须唯一。
我们前面已经学习了很多指针,指针指向这一块空间我们可以通过指针找到指针所指向的那个空间,对那个空间的内容进行操作。
文件类型指针简称为文件指针,被使用的文件都会在内存中开辟一块文件信息的区域。存放了比如说文件的名称大小状态位置。非常明显这些信息是保存在一个结构体中的,结构体重命名为FILE。
在vs2013下的实例
struct _iobuf {
char* _ptr;
int _cnt;
char* _base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char* _tmpfname;
};
typedef struct _iobuf FILE;
fopen
函数原型:
1.返回值是一个文件类型的指针创建一个FILE* pf 文件类型指针变量可以通过pf去找到这个文件空间进行一些操作。我们也称这个文件空间为文件信息区pf是指向这个文件信息区域的。如果fopen返回值是一个NULL说明文件信息区创建失败
2.const charfilename 是我们的文件名称,有两种输入方式一种是绝对路径,一种是相对路径。
绝对路径:这个文件的位置包括有盘符+找文件过程中的文件+文件名称+后缀名称。
相对路径是从当前程序代码的文件开始进行寻找,
.\文件夹\文件名称.后缀名
…\上一个目录中的文件夹\文件名称.后缀名
3.const char mode 这个是对我们对文件操作的一个规定。文件打开模式
下面就是我们这个参数的可能取值要看你如何去使用这个文件去自己决定的.
文件使用方式---- 含义------------------------------------------------- 如果指定文件不存在
“r”(只读) 为了输入数据,打开一个已经存在的文本文件 ----------出错
“w”(只写) 为了输出数据,打开一个文本文件----------- 建立一个新的文件
“a”(追加) 向文本文件尾添加数据 --------------------------建立一个新的文件
“rb”(只读) 为了输入数据,打开一个二进制文件 -------出错
“wb”(只写) 为了输出数据,打开一个二进制文件------- 建立一个新的文件
“ab”(追加) 向一个二进制文件尾添加数据 ----------------建立一个新的文件
“r+”(读写) 为了读和写,打开一个文本文件 -------------出错
“w+”(读写) 为了读和写,建议一个新的文件------------- 建立一个新的文件
“a+”(读写) 打开一个文件,在文件尾进行读写 ----------建立一个新的文件
“rb+”(读写) 为了读和写打开一个二进制文件 ------------出错
“wb+”(读写) 为了读和写,新建一个新的二进制文件— 建立一个新的文件
“ab+”(读写) 打开一个二进制文件,在文件尾进行读和写 ------建立一个新的文件
补充概念:流–>抽象的概念
fopen的文件的文件信息区相对于一个流,程序执行的过程中默认打开三个流的分别是:
stdin标准输入流–>scanf getchar getch
stdout标准输出流—>printf putchar
stderror标准错误流
这个流是直接与程序执行过程中的内存进行实时的交互.
功能------------ 函数名------------ 适用于
字符输入函数-- fgetc ---------------所有输入流
字符输出函数 --fputc ---------------所有输出流
文本行输入函数-- fgets------------ 所有输入流
文本行输出函数 --fputs ------------所有输出流
格式化输入函数 --fscanf ----------所有输入流
格式化输出函数 --fprintf -----------所有输出流
二进制输入 --fread ------------------文件
二进制输出 —fwrite ------------------文件
接下来我们进行一组一组的使用和介绍!
1.fputc是有两个参数int character 是我们输入的字符,我们是是int类型是因为是使用Ascii码的值进行传输.
2.文件输出流FILE * stream
3.返回值是当我们不去输入字符到文件流中就会返回EOF
1.是有1个参数.
2.文件输出流FILE * stream
3.返回值是当我们从文件流中拿不出就会返回EOF,正常情况下是返回获取到的字符的ascia码的值。
1.是有两个参数const char* str是我们输入的字符串,我们是是int类型是因为是使用Ascii码的值进行传输.
2.文件输出流FILE * stream
3.返回值是当我们正常输入字符串到文件流中就会返回数字0;
>1.fputc是有三个参数 char* str 是我们从文件中拿出来的字符串需要放置的位置.num-1个字符输入到内存中的str中。
2.文件输出流FILE * stream
3.返回值是当我们不去输入字符串到文件流中就会返回NULL;
总结一个fgets结束有两种情况:
1.根据num-1的个数在一行里这一行的字符没有读取结束但是num-1的数值已经到了就结束这个fgets
2.我们的num-1的个数足够走完一行,走到行尾这个函数也结束。
二进制的输入输出函数
1.size_t函数返回值 实际写入到我们的文件中的数据个数。
2.const void* ptr ,从这个变量的指针中获取数据放到我们的文件流中。
3.size_t size类型大小单位是字节
4.size_t count 是我们想要传入文件流中的这个类型变量的多少个。
4.FILE * stream我们的文件流。
1.size_t函数返回值 实际拿出来到我们的内存中的数据个数。
2.const void* ptr ,从文件流中获取到的数据放到我们的这个类型指针中。
3.size_t size类型大小单位是字节
4.size_t count 是我们想要从文件流中拿出来的这个类型变量的多少个。
4.FILE * stream我们的文件流。
5.返回出来的数值去和你想要拿出来的数值去比较就可以判断文件是否已经读空。
对比一组函数:
scanf/fscanf/sscanf
printf/fprintf/sprintf
前面4张图片return 0 前面要加是一个fclose(pf)
1.文件流。
2.long int offset 偏移量这个偏移量是可以根据数值的正负去确定方向的。
3.SEEK_SET 从头开始
SEEK_CUR 从当前位置开始
SEEK_END 从尾开始
作用:调整我们访问文件流的偏移量使我们可以去按照自己的想法去访问。
重置当前偏移量为0.
根据数据的组织形式,数据文件被称为文本文件或者二进制文件。
数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。
如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文
本文件。
一个数据在内存中是怎么存储的呢?
字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。
如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而
二进制形式输出,则在磁盘上只占4个字节。
牢记:在文件读取过程中,不能用feof函数的返回值直接来判断文件的是否结束。
feof 的作用是:当文件读取结束的时候,判断是读取结束的原因是否是:遇到文件尾结束。
#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))
{
printf("Error reading test.bin: unexpected end of file\n");
}
else if (ferror(fp))
{
perror("Error reading test.bin");
}
}
fclose(fp);
}
ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序
中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装
满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓
冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根
据C编译系统决定的。
文件缓冲区的存在有什么用处呢?
假设没有文件缓冲是不是内存和文件会一直进行数据的交流,频繁的交流会导致他们本身的事情干不了。
程序进度缓慢
1.fflush可以刷新缓冲区
2.fclose函数可以刷新缓冲区
#include
#include
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;
}
1.第一次输入人的信息,结尾应该有一个文件去保存数据。
2.初始化的时候考虑从文件拿出来数据应该和程序初始化malloc的大小要大,并且考虑malloc函数增容的问题和ps->sz 和ps->capclity 变化的问题。
今天的分享就到这里了谢谢大家的阅读希望文章可以帮助到你!