我们使用文件的原因是:想要把数据直接存放在电脑的硬盘上面,实现数据的持久化
一、什么是文件?
-
程序文件
程序文件主要指的是由程序开发产生的文件,包括:
- 源程序文件 :包含代码的文件,扩展名通常为
.c
- 目标文件 :由编译器将源代码编译生成的中间文件,扩展名通常为
.obj
(在Windows系统上)(linux的我之前写过来着) - 可执行文件 :由链接器生成的最终可以直接运行的文件,扩展名为
.exe
- 源程序文件 :包含代码的文件,扩展名通常为
-
数据文件
数据文件是存储数据的文件 ,数据可以是程序运行时 产生的或需要读入程序中的。它们的内容可以是文本、数字、二进制数据等
-
文件名
文件名通常包括文件路径、文件名主干和文件后缀:
- 文件路径:指定文件所在的目录位置(如
C:/Documents
) - 文件名主干:文件的主要名称部分(如
myfile
) - 文件后缀:文件的类型标识(如
.txt
、.bin
)
- 文件路径:指定文件所在的目录位置(如
二、文件的打开和关闭
-
文件指针
在C语言中,每个文件在被打开时,系统会在内存中为该文件分配一个文件信息区 。这个文件信息区存储了与文件相关的信息,包括文件名、文件指针位置、文件状态等。为了操作这些文件信息,我们通过一个类型为
FILE
的结构体指针来引用文件。FILE
是由标准库定义的结构体类型,包含了文件的状态信息。不同编译器对FILE
结构体的定义可能略有不同,但其作用一致。
-
文件的打开和关闭
使用
fopen
函数打开文件,使用fclose
函数关闭文件FILE *fopen(const char *filename, const char *mode); int fclose(FILE *stream);
filename
:文件的名称(包括路径)
mode
:文件的打开方式,如下:"r"
:以只读方式打开文件,文件必须存在"w"
:以写入方式打开文件,若文件存在则覆盖,不存在则创建"a"
:以追加方式打开文件,若文件存在则在文件末尾追加,不存在则创建"rb"
:以二进制模式读取文件"wb"
:以二进制模式写入文件"r+"
:以读写模式打开文件,文件必须存在"w+"
:以读写模式打开文件,如果文件存在则清空内容,如果不存在则创建- 类型挺多的,你记住如果文件不存在就报错的有:r、rb、ab、r+、rb+就行
#include <stdio.h>
int main() {
// 打开文件 example.txt,使用 "r" 模式,表示只读
FILE *fp = fopen("example.txt", "r");
if (fp == NULL) {
// 错误处理,如果文件打开失败,返回1
printf("无法打开文件\n");
return 1;
}// 文件操作部分(如读取、写入) // 关闭文件,释放资源 fclose(fp); return 0;
}
三、文件的顺序读写
文件的顺序读写是指从文件的开头开始按顺序进行读写操作,常用函数包括 fread
、fwrite
、fgets
、fputs
等
读操作
-
fgetc()
:从文件中读取一个字符 -
fgets()
:从文件中读取一行文本 -
fread()
:从文件中读取一块数据#include <stdio.h>
int main() {
FILE *fp = fopen("example.txt", "r");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}char ch; // 使用 fgetc 逐字符读取文件内容 while ((ch = fgetc(fp)) != EOF) { putchar(ch); // 将读取的字符输出到控制台 } fclose(fp); return 0;
}
这里,fgets
从文件中读取一行,并存储在 buffer
中,直到遇到换行符或者达到 sizeof(buffer)
#include <stdio.h>
int main() {
FILE *fp = fopen("example.txt", "r");
if (fp == NULL) {
perror("无法打开文件");
return 1;
}
char buffer[256];
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
printf("%s", buffer);
}
fclose(fp);
return 0;
}
写操作
-
fputc()
:向文件中写入一个字符 -
fputs()
:向文件中写入一个字符串 -
fwrite()
:向文件中写入一块数据#include <stdio.h>
int main() {
FILE *fp = fopen("example.txt", "w");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}// 使用 fputs 写入字符串到文件 fputs("Hello, world!\n", fp); fclose(fp); return 0;
}
四、文件的随机读写
在文件的任意位置读写称为随机读写,C语言提供了三个函数用于文件的定位和读取:
fseek()
fseek()
函数用于移动文件指针到文件中的某个位置:
int fseek(FILE *stream, long offset, int whence);
stream
:文件指针offset
:移动的字节数whence
:指针移动的基准位置:SEEK_SET
:文件开头SEEK_CUR
:当前文件指针位置SEEK_END
:文件末尾
ftell()
ftell()
返回文件指针当前的位置:
long ftell(FILE *stream);
rewind()
rewind()
函数将文件指针移回文件开头
void rewind(FILE *stream);
举个例子:
#include <stdio.h>
int main() {
FILE *fp = fopen("example.txt", "r");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
fseek(fp, 10, SEEK_SET); // 将文件指针移动到文件开头之后的第10个字节
char ch = fgetc(fp);
printf("字符:%c\n", ch);
fclose(fp);
return 0;
}
下面是对 ftell
和 fseek
的使用示例:
#include <stdio.h>
int main() {
FILE *fp = fopen("example.txt", "r");
if (fp == NULL) {
perror("无法打开文件");
return 1;
}
fseek(fp, 0, SEEK_END); // 移动到文件末尾
long size = ftell(fp); // 获取文件大小
printf("文件大小: %ld 字节\n", size);
rewind(fp); // 返回文件开头
char ch;
while ((ch = fgetc(fp)) != EOF) {
putchar(ch);
}
fclose(fp);
return 0;
}
这里使用 fseek
将文件指针移动到文件末尾,并用 ftell
获取文件大小
五、文本文件和二进制文件
-
文本文件
文本文件是指存储文本数据的文件,每个字符以ASCII码的形式存储。常用的操作模式包括
"r"
、"w"
等 -
二进制文件
二进制文件直接存储数据的二进制格式,可以包含任意类型的文件。其操作模式包括
"rb"
、"wb"
等#include <stdio.h> int main() { // 写入二进制文件 FILE *fp = fopen("example.bin", "wb"); if (fp == NULL) { printf("无法打开文件\n"); return 1; } int num = 12345; fwrite(&num, sizeof(int), 1, fp); // 将整型变量写入文件 fclose(fp); // 读取二进制文件 fp = fopen("example.bin", "rb"); if (fp == NULL) { printf("无法打开文件\n"); return 1; } int read_num; fread(&read_num, sizeof(int), 1, fp); // 从文件读取整型变量 printf("读取的数字是:%d\n", read_num); fclose(fp); return 0; }
六、文件读取结束的判定
在读取文件时,经常需要判断文件是否已到末尾,feof()
是常用的判断函数
int feof(FILE *stream);
feof()
当文件指针到达文件末尾时返回非0值,否则返回0。但需要注意的是,feof()
只有在尝试读取后才会返回EOF状态,不能在读取前判断
#include <stdio.h>
int main() {
FILE *fp = fopen("example.txt", "r");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
while (!feof(fp)) {
char ch = fgetc(fp);
if (feof(fp)) break; // 读取后判断是否到达文件末尾
putchar(ch);
}
fclose(fp);
return 0;
}
七、文件缓冲区
文件缓冲区的存在有助于提升程序的性能,降低系统调用频率,同时提高数据一致性和安全性,并提供了灵活的控制机制
C语言中的文件操作默认是缓冲的,使用 setbuf()
和 setvbuf()
函数可以控制文件缓冲行为。文件缓冲分为三种模式:
-
全缓冲:数据积累到缓冲区满时才会写入。
-
行缓冲:遇到换行符时数据会写入。
-
无缓冲:每次操作都会立即写入或读取
#include <stdio.h>
int main() {
FILE *fp = fopen("example.txt", "w");
if (fp == NULL) {
perror("无法打开文件");
return 1;
}char buf[BUFSIZ]; setvbuf(fp, buf, _IOFBF, BUFSIZ); // 设置为全缓冲模式 fputs("缓冲写入测试\n", fp); fclose(fp); return 0;
}
因为有缓冲区存在,所以在C语言操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件