目录
什么是文件
磁盘上的文件是文件
为什么使用文件
存储信息不受外界因素影响,如断电,故障关机等。具有良好的保存性。
譬如我们C语言实现的通讯录,在运行程序时添加的联系人信息,当我们关闭它重新运行时,联系人信息又没有了,这非常不方便,加入我们可以将信息储存到文件中,它就不会受到影响,会一直安安稳稳的呆在文件里,当我们再次运行程序时,将信息从文件中拷入,我们就不必再进行一次存储了,这才是合理的方式。
如何使用文件
文件类型和文件指针
当我们打开文件时,会在内存中开辟一个文件信息区,用来存放文件的相关数据,这些数据被保存在结构体变量中,此结构体类型被统称为FILE类型。
文件的打开和关闭
那么接下来要向大家介绍两个函数:
FILE *fopen( const char *filename, const char *mode );
作用:打开文件
filename:文件名(也可以放入文件路径)
mode:打开方式
打开方式:
int fclose( FILE *stream );
而关闭文件用fclose函数,只需要传入文件指针便可。
和free很相似,大家不会把动态内存忘记了吧,不会吧不会吧???
代码示例:
int main()
{
//打开文件
FILE* pf = fopen("notepad.txt", "w");//只写
if (pf == NULL)
{
perror("fopen");
return;
}
//文件操作
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
如何操作文件
我们有了文件的打开方式,那么我们自然应该根据打开方式来对文件今昔能够与之对应的操作。
接下来注意为大家演示代码。
代码示例:
1.fputc
#include<stdio.h>
int main()
{
//int fputc( int c, FILE *stream ); 向文件输出 写入文件
//打开文件
FILE* pf = fopen("notepad.txt", "w");//只写
if (pf == NULL)
{
perror("fopen");//报错
return;
}
int i = 0;
for (i = 'a'; i <= 'z'; i++)
{
//文件操作 - 向文件写入数据
fputc(i, pf);
fputc(' ', pf);
}
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
2.fgets
//int fgetc( FILE *stream ); 从文件中取出数据
//返回EOF表示错误或文件结束
int main()
{
//打开文件
FILE* pf = fopen("notepad.txt", "r");//只读
if (pf == NULL)
{
perror("fopen");//报错
return;
}
//文件操作
int ch = 0;
while ((ch = fgetc(pf)) != EOF)
{
fputc(ch, stdout);
}
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
注意:不管是fputc还是fgetc在输出与输入时,在输出(输入)一个字符后,光标自动跳到下一个位置。
3.fgets与fputs 和fgetc与fputc用法相同 这里不给大家做演示了,留给大家练习。区别只在于fgets和fputs是对文本行进行输入输出。
4.格式化输入函数 - fscanf 与格式化输出函数 - fprintf
这里给大家用一个代码进行演示,以结构体为例
typedef struct person
{
int age;
char name[16];
int height;
}person;
person p1 = { 22,"张三",130 };
person p2 = { 0 };
int main()
{
//打开文件
FILE* pf = fopen("notepad.txt", "w");//只写
if (pf == NULL)
{
perror("fopen");//报错
return;
}
//文件操作
fprintf(pf, "%d %s %d", p1.age, p1.name, p1.height);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
typedef struct person
{
int age;
char name[16];
int height;
}person;
person p1 = { 22,"张三",130 };
person p2 = { 0 };
int main()
{
//打开文件
//FILE* pf = fopen("notepad.txt", "w");//只写
FILE* pf = fopen("notepad.txt", "r");//只读
if (pf == NULL)
{
perror("fopen");//报错
return;
}
//文件操作
/*fprintf(pf, "%d %s %d", p1.age, p1.name, p1.height);*/
fscanf(pf, "%d %s %d", &(p2.age), p2.name, &(p2.height));
printf("%d %s %d", p2.age, p2.name, p2.height);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
将文件中的格式化数据去除并保存在了p2中。
5.二进制输入 - fread 与 二进制输出 - fwrite
fread
从流中读取数据。
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
返回值:
Fread返回实际读取的完整条目的数量,如果发生错误,或者如果在到达count之前遇到文件的末尾,则可能小于count。使用feof或ferror函数来区分读错误和文件结束条件。如果size或count为0,则fread返回0,且缓冲区内容不变。
buff
用于数据大小的存储位置size
项目大小(以字节计数)count
要读取的最大条目数stream
指向FILE结构的指针
fwrite
将数据写入流。
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
返回值:
Fwrite返回实际写入的完整项数,如果发生错误,这个数可能小于count。此外,如果发生错误,则无法确定文件位置指示器。
buff
指向要写入的数据大小的指针
size
项目大小(以字节计数)count
要写入流的最大项目数stream
指向FILE结构的指针
代码示例可跳转到文本文件和二进制文件中进行查看。
sscanf 和 sprintf
sscanf:将字符串中的格式化数据提取出来
sprintf:将格式化数据转换成字符串
fprintf:格式化输出数据,适用于所有输出流
fscanf:格式化输入数据,适用于所有输入流
printf:打印格式化输出到标准输出流
scanf:从标准输入流读取格式化数据
typedef struct person
{
int age;
char name[16];
int height;
}person;
person p1 = { 22,"张三",130 };
person p2 = { 0 };
int main()
{
char buff[66] = { 0 };
sprintf(buff, "%d %s %d", p1.age, p1.name, p1.height);
printf("%s\n", buff);//以字符串形式打印
sscanf(buff, "%d %s %d", &(p2.age), p2.name, &(p2.height));
printf("%d %s %d\n", p2.age, p2.name, p2.height);//以结构体的形式进行打印
return 0;
}
文件的随机读写 - fseek
fseek
将文件指针移动到指定位置
int fseek( FILE *stream, long offset, int origin );
stream
指向FILE结构偏移量的指针
offset
从原点开始的字节数origin
初始位置SEEK_CUR
文件指针的当前位置
SEEK_END
文件结束
SEEK_SET
开头的文件
int main()
{
//打开文件
FILE* pf = fopen("notepad.txt", "w");//只写
if (pf == NULL)
{
perror("fopen");//报错
return;
}
//文件操作
int i = 0;
for (i = 'K'; i <= 'Q'; i++)
{
fputc(i, pf);
}
fseek(pf, 3, SEEK_SET);//移动指针
fputc('w', pf);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
获取文件指针的当前位置 - ftell
如何让指针快速回到起始位置呢
很多同学可能会想到用fseek函数,偏移量为0,传入SEEK_SET,这样就可以让指针指向起始地址了,很好,但是还不够好,C语言为我们提供了一个函数 - rewind,只要将文件指针传入即可。
文本文件和二进制文件
数据在内存中以二进制的方式进行存储,如果数据不加转换的输出到外存,那么就是二进制文件;
如果以ASCII值的形式进行存储的文件,那么就是文本文件。
此时,数据是以二进制的方式存储的,因此我们看不懂这是个什么玩意儿非常的正常,接下来我教大家如何查看二进制文件。
右击源文件 -> 添加 -> 现有项 -> ->右击 notepad.txt -> 打开方式 ->
->
文件读取结束的判定
feo 与 ferror
不能根据feo的返回值来判断文件是否读取结束,而是应用于判断读取结束的原因,是因为读取到文件末尾而结束,还是读取失败而结束。
1.文本文件是否读取结束,判断返回值为EOF或NULL
fgetc:EOF
fgets:NULL
2.二进制读取文件结束,判断返回值是否小于实际要读取的个数
fread
feo:当前位置不是文件末尾,返回0
ferror:文件读取失败返回非零值,如果没有错误则返回0
文件缓冲区
ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。