文章目录
一.认识了解文件
1.文件的概念
计算机中,文件是指计算机存储设备中的一个数据集合,以某种方式组织和命名并可由计算机系统识别和处理。在程序设计中,我们⼀般谈的⽂件有两种:程序⽂件、数据⽂件(从⽂件功能的⻆度来分类的)。
2.文件的分类
a.程序文件
程序⽂件包括源程序⽂件(后缀为.c),⽬标⽂件(windows环境后缀为.obj),可执⾏程序(windows环境后缀为.exe)。
b.数据文件
⽂件的内容不⼀定是程序,⽽是程序运⾏时读写的数据,⽐如程序运⾏需要从中读取数据的⽂件,或者输出内容的⽂件。
3.文件名
⼀个⽂件要有⼀个唯⼀的⽂件标识,以便⽤⼾识别和引⽤。
⽂件名包含3部分:⽂件路径+⽂件名主⼲+⽂件后缀
列如:D:\code\seven_c.txt
其中,文件路径:D:\code,文件主干:seven_c,文件后缀:txt。
4.二进制文件和文本文件
a.二进制文件
二进制文件是一种以二进制形式存储的文件,其中的数据以字节序列的形式表示。与文本文件不同,二进制文件中的数据不以可读的字符形式表示,而是以字节的形式直接存储。
b.文本文件
文本文件是一种常见的文件类型,其中的数据以文本形式表示,并且可以由人类读取和理解。与二进制文件不同,文本文件中的数据以字符的形式存储,通常使用ASCII码或Unicode编码来表示字符。
⼀个数据在内存中是怎么存储的呢?
字符⼀律以ASCII形式存储,数值型数据既可以⽤ASCII形式存储,也可以使⽤⼆进制形式存储。
如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占⽤5个字节(每个字符⼀个字节),而二进制形式输出,则在磁盘上只占4个字节(VS2019测试)。
测试代码:
a.C语言
#include <stdio.h>
int main()
{
int a = 10000; // 定义一个整数变量a,赋值为10000
FILE * pf = fopen("test.txt", "wb"); // 打开一个名为test.txt的二进制文件,写入模式
fwrite(&a, 4, 1, pf); // 将a以4字节大小的二进制形式写入文件中
fclose(pf); // 关闭文件
pf = NULL; // 将文件指针置为空,避免悬挂指针
return 0;
}
b.c++
#include <cstdio>
int main()
{
int a = 10000; // 定义一个整数变量a,赋值为10000
FILE* pf = std::fopen("test.txt", "wb"); // 以写入二进制方式打开文件test.txt
std::fwrite(&a, 4, 1, pf); // 将a以4字节大小的二进制形式写入文件中
std::fclose(pf); // 关闭文件
pf = NULL; // 将文件指针置为空,避免悬挂指针
return 0;
}
在VS2022上打开二进制文件:
二.文件的打开和关闭
1.文件指针
文件指针是C语言中用于操作文件的一个重要概念,它是一个指针变量,用于指向文件的信息区。
这个信息区通常是一个名为FILE的结构体,包含了文件的特征、当前状态以及文件的相关信息,如文件名、文件状态、当前位置、缓冲区的地址和大小等。通过文件指针,程序可以对文件进行各种操作,如读取和写入数据。在C语言中,文件指针通常定义为指向FILE结构体的指针,例如通过声明“FILE *fp;”来创建一个文件指针fp。
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;
注:不同环境下的file类型有些许不同.
FILE* pf;//⽂件指针变量
2.文件的打开和关闭
FILE * fopen ( const char * filename, const char * mode ); //打开文件
int fclose ( FILE * stream );
mode只是文件的打开模式.
测试样例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
FILE* pf;
pf = fopen("text.txt", "w");
if (pf != NULL)
{
fputs("I'm fine", pf);
fclose(pf);
}
else
{
perror("Error");
}
return 0;
}
运行结果:
三.文件的顺序读写
顺序读写函数介绍
上⾯说的适⽤于所有输⼊流⼀般指适⽤于标准输⼊流和其他输⼊流(如⽂件输⼊流);所有输出流⼀般指适⽤于标准输出流和其他输出流(如⽂件输出流)。
四. 文件的随机读写
1. fseek
函数介绍:
函数参数 :
stream:指向文件标识流的对象。
offset:二进制文件:偏移的字节数起源 .
文本文件:零或返回的值 位置函数 .
origin:文件指针定位的位置
SEEK_SET:文件开头.
SEEK_CUR:文件指针的当前位置
SEEK_END:文件结尾.
函数功能 : 根据⽂件指针的位置和偏移量来定位⽂件指针。
测试样例 :
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main ()
{
FILE * pFile;
pFile = fopen ( "example.txt" , "wb" );
fputs ( "This is an apple." , pFile );
fseek ( pFile , 9 , SEEK_SET );
fputs ( " sam" , pFile );
fclose ( pFile );
return 0;
}
运行结果:
2.ftell
函数介绍:
函数参数:
stream:指向文件标识流的对象。
函数功能: 返回⽂件指针相对于起始位置的偏移量
测试样例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
FILE* pf;
long size;
pf = fopen("myfile.txt", "w");
fputs("abcdefg", pf);
//fputc("sam", pf);
if (pf == NULL) perror("Error opening file");
else
{
// fputc("sam", pf);
fseek(pf,4, SEEK_SET);
size = ftell(pf);
fclose(pf);
printf("Size of myfile.txt: %ld bytes.\n", size);
}
return 0;
}
运行结果:
3.rewind
函数介绍:
函数参数:
stream:指向文件标识流的对象。
函数功能: 让⽂件指针的位置回到⽂件的起始位置.
测试样例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int n;
FILE* pf;
char buffer[27];
pf = fopen("myfile.txt", "w+");
for (n = 'A'; n <= 'Z'; n++)
fputc(n, pf);
rewind(pf);
fread(buffer, 1, 26, pf);
fclose(pf);
buffer[26] = '\0';
puts(buffer);
return 0;
}
运行结果:
五.文件结束的判断
1.feof
函数参数:
stream:指向文件标识流的对象。
函数功能: 检测流上的文件结束符.
测试样例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
FILE* file;
char ch;
// 以读取模式打开文件
file = fopen("example.txt", "r");
if (file == NULL)
{
perror("文件打开失败");
return 1;
}
// 循环读取文件,直到到达文件尾
while (1)
{
ch = fgetc(file);
if (feof(file))
{
break; // 如果到达文件尾,跳出循环
}
printf("%c", ch); // 打印字符
}
// 关闭文件
fclose(file);
return 0;
}
运行结果:
2.ferror
函数参数:
stream:指向文件标识流的对象。
函数功能: 检查文件操作是否出现错误.
perror() 是一个 C 和 C++ 标准库函数,用于打印你的程序中发生的最近一次系统错误的描述
当你调用 fopen()时,如果出现问题,系统会在内部变量 errno 中存储一个错误代码。然后,可以调用 perror() 来查看这个错误代码对应的文本描述
测试样例:
#include <stdio.h>
int main() {
FILE* file;
// 以写入模式打开文件
file = fopen("example.txt", "w");
if (file == NULL) {
perror("文件打开失败");
return 1;
}
// 尝试写入文件
if (fprintf(file, "Hello, World!") < 0) {
if (ferror(file)) {
perror("文件写入失败");
// 关闭文件
fclose(file);
return 2;
}
}
// 关闭文件
fclose(file);
printf("文件成功写入。\n");
return 0;
运行结果:
被错误使用的 feof
在⽂件读取过程中,不能⽤feof函数的返回值直接来判断⽂件的是否结束。
feof 的作⽤是:当⽂件读取结束的时候,判断是读取结束的原因是否是:遇到⽂件尾结束。
- ⽂本⽂件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者NULL ( fgets )
例如:
• fgetc 判断是否为 EOF .
• fgets 判断返回值是否为 NULL . - ⼆进制⽂件的读取结束判断,判断返回值是否⼩于实际要读的个数。
例如:
• fread判断返回值是否⼩于实际要读的个数。
六.文件缓冲区
ANSIC 标准采⽤“缓冲⽂件系统”处理的数据⽂件的,所谓缓冲⽂件系统是指系统⾃动地在内存中为程序中每⼀个正在使⽤的⽂件开辟⼀块“⽂件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才⼀起送到磁盘上。如果从磁盘向计算机读⼊数据,则从磁盘⽂件中读取数据输⼊到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的⼤⼩根据C编译系统决定的。
这⾥可以得出⼀个结论:
因为有缓冲区的存在,C语⾔在操作⽂件的时候,需要做刷新缓冲区或者在⽂件操作结束的时候关闭⽂件。如果不做,可能导致读写⽂件的问题