当前位置: 首页 > news >正文

文件操作(C语言版)

目录

一、为什么使用文件

二、什么是文件

2.1、程序文件

2.1.1、源代码文件

2.1.2、头文件与接口

2.1.3、脚本文件

2.1.4、编译与构建文件

2.1.5、配置文件

2.1.6、数据与数据库文件

2.1.7、其他特殊文件

2.2、数据文件

2.3、文件名

2.3.1、文件名的基本构成

2.3.2、文件路径

三、二进制文件和文本文件

 四、文件的打开和关闭

4.1、流和标准流

4.1.1、流

4.1.2、标准流

4.2、文件指针

4.3、文件的打开和关闭

五、文件读写函数

5.1、fgetc与fputc

1. fgetc 函数​​

2. fputc 函数​​

5.2、fgets与fputs

1. fgets 函数​​

​​2. fputs 函数​​

5.3、fprintf与fscanf

1. fprintf 函数​​

2. fscanf 函数​​

5.4、sprintf与sscanf

2. sscanf 函数​​

5.5、fread与fwrite

1. fwrite 函数​​

2. fread 函数​​

5.6、总结

六、文件的随机读取

 6.1、rewind函数

6.2、fseek 函数​​

6.3、ftell 函数​​

七、文件读取结束的判定

7.1、feof函数

7.2、ferror函数

一、为什么使用文件

        如果没有⽂件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失了,等再次运⾏程序,是看不到上次程序的数据的,如果要将数据进⾏持久化的保存,我们可以使⽤⽂件。

二、什么是文件

磁盘(硬盘)上的⽂件是⽂件。
但是在程序设计中,我们⼀般谈的⽂件有两种:程序⽂件、数据⽂件(从⽂件功能的⻆度来分类
的)。

2.1、程序文件

2.1.1、源代码文件

后缀名语言示例文件
.cC源语言test.c
.cppCpp源代码test.cpp
.javaJava源代码test.java
.pypython脚本test.py
.goGo源代码test.go
.rsRust源代码test.rs
.mMATLAB源代码test.m
.swiftSwift源代码test.swift

2.1.2、头文件与接口

后缀名用途示例文件
.hC/Cpp头文件test.h
.hppCpp头文件test.hpp
.inc通用头文件test.inc

2.1.3、脚本文件

后缀名用途示例文件
.sh

Shell脚本(Linux/Unix)

test.sh
.batWindows批处理脚本test.bat
.pslPowerShell脚本test.psl
.vbsVBScript脚本test.vbs

2.1.4、编译与构建文件

后缀名用途示例文件
.oC/Cpp编译产生的文件test.o
.objWindows下的目标文件test.obj
.exeWindows可执行文件test.exe
.a静态库(Linux/Unix)test.a
.so动态库(Unix)test.so
.dllWindows动态链接库tets.dll
.jarJava打包文件test.jar

2.1.5、配置文件

后缀名用途示例文件
.jsonJSON配置文件test.json
.ymlYANL配置文件test.yml
.ini传统配置文件test.ini
.env环境变量文件test.env

2.1.6、数据与数据库文件

后缀名用途示例文件
.csv逗号分隔数据文件test.csv
.sqlSQL脚本文件test.sql
.db数据库文件(如SQLite)test.db
.xmlXML数据文件test.xml

2.1.7、其他特殊文件

后缀名用途示例文件
.gitignoreGit忽律规则文件test.gitignore
.dockerfileDocker镜像构建文件test.dockerfile
.mdMarkdown文档test.md
.log日志文件test.log

2.2、数据文件

        ⽂件的内容不⼀定是程序,⽽是程序运⾏时读写的数据,⽐如程序运⾏需要从中读取数据的⽂件,或者输出内容的⽂件。本章讨论的是数据⽂件。
        在以前各章所处理数据的输⼊输出都是以终端为对象的,即从终端的键盘输⼊数据,运⾏结果显⽰到显⽰器上。
        其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使⽤,这⾥处理的就是磁盘上⽂件。

2.3、文件名

2.3.1、文件名的基本构成

文件名通常由 ​​主文件名​​ 和 ​​扩展名(后缀)​组成,格式为:

主文件名.扩展名

 例如:report.docxmain.cindex.html

1. 主文件名​

  • ​作用​​:标识文件内容或用途(如 projectdata)。
  • ​命名规则​​:
    • 允许字符:字母、数字、-_(具体取决于操作系统)。
    • 长度限制:Windows(260字符)、Linux(255字符)。
    • 大小写敏感:Linux区分大小写(File.txt ≠ file.txt),Windows不区分。

​2. 扩展名(后缀)​

  • ​作用​​:指示文件类型(如 .txt 表示文本文件,.exe 表示可执行文件)。
  • ​常见扩展名​​:
    • 文本文件:.txt.csv
    • 程序文件:.c.py.java
    • 可执行文件:.exe(Windows), .out(Linux)

2.3.2、文件路径

文件通过 ​​路径(Path)​​ 定位,分为两种形式:

​1. 绝对路径​

  • ​定义​​:从根目录开始的完整路径。
  • ​示例​​:
    • Windows: C:\Users\Alice\Documents\report.docx
    • Linux: /home/alice/docs/report.txt

​2. 相对路径​

  • ​定义​​:相对于当前工作目录的路径。
  • ​示例​​(假设当前目录为 /home/alice):
    • ./docs/report.txt./ 表示当前目录)
    • ../downloads/file.zip../ 表示上级目录)

​3. 特殊路径符号

符号含义示例
.当前目录./test.sh
..上级目录../test.yml
~用户主目录~/Downloads/file.zip
/根目录(Linux)/etc/hosts
\

路径分隔符(Windows)

C:\Windows\system32

三、二进制文件和文本文件

        根据数据的组织形式,数据⽂件被称为⽂本⽂件⼆进制⽂件
数据在内存中以⼆进制的形式存储,如果不加转换的输出到外存的⽂件中,就是⼆进制⽂件。
如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的⽂件就是⽂本⽂件。
        ⼀个数据在⽂件中是怎么存储的呢?
        字符⼀律以ASCII形式存储,数值型数据既可以⽤ASCII形式存储,也可以使⽤⼆进制形式存储。如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占⽤5个字节(每个字符⼀个字节),⽽⼆进制形式输出,则在磁盘上只占4个字节。

 四、文件的打开和关闭

4.1、流和标准流

4.1.1、流

        我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输⼊输出操作各不相同,为了⽅便程序员对各种设备进⾏⽅便的操作,我们抽象出了流的概念,我们可以把流想象成流淌着字符的河。C程序针对⽂件、画⾯、键盘等的数据输⼊输出操作都是通过流操作的。
        ⼀般情况下,我们要想向流⾥写数据,或者从流中读取数据,都是要打开流,然后操作。

4.1.2、标准流

那为什么我们从键盘输⼊数据,向屏幕上输出数据,并没有打开流呢?

那是因为C语⾔程序在启动的时候,默认打开了3个流:

  • stdin - 标准输⼊流,在⼤多数的环境中从键盘输⼊,scanf函数就是从标准输⼊流中读取数据。
  • stdout - 标准输出流,⼤多数的环境中输出⾄显⽰器界⾯,printf函数就是将信息输出到标准输出流中。
  • stderr - 标准错误流,⼤多数环境中输出到显⽰器界⾯。
这是默认打开了这三个流,我们使⽤scanf、printf等函数就可以直接进⾏输⼊输出操作的。
stdin、stdout、stderr 三个流的类型是: FILE * ,通常称为⽂件指针
C语⾔中,就是通过 FILE* 的⽂件指针来维护流的各种操作的。

 

4.2、文件指针

缓冲⽂件系统中,关键的概念是“⽂件类型指针”,简称“⽂件指针”
每个被使⽤的⽂件都在内存中开辟了⼀个相应的⽂件信息区,⽤来存放⽂件的相关信息(如⽂件的名字,⽂件状态及⽂件当前的位置等)。这些信息是保存在⼀个结构体变量中的。该结构体类型是由系统声明的,取名 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*的指针变量:

 FILE* pf;//⽂件指针变量

         定义pf是⼀个指向FILE类型数据的指针变量。可以使pf指向某个⽂件的⽂件信息区(是⼀个结构体变量)。通过该⽂件信息区中的信息就能够访问该⽂件。也就是说,通过⽂件指针变量能够间接找到与它关联的⽂件。

⽐如:

4.3、文件的打开和关闭

⽂件在读写之前应该先打开⽂件,在使⽤结束之后应该关闭⽂件

在编写程序的时候,在打开⽂件的同时,都会返回⼀个FILE*的指针变量指向该⽂件,也相当于建⽴了指针和⽂件的关系。

ANSIC 规定使⽤ fopen 函数来打开⽂件, fclose 来关闭⽂件。

  //打开⽂件

  FILE * fopen ( const char * filename, const char * mode );
  // 关闭⽂件
  int fclose ( FILE * stream );

mode表⽰⽂件的打开模式,下⾯都是⽂件的打开模式:

 

 实例代码:

#include <stdio.h>
#include <stdlib.h>typedef struct info
{char name[20];int age;int num;char address[20];
}info;
int main()
{info stu[3];for (int i = 0; i < 3; i++){scanf("%s %d %d %s", stu[i].name, &stu[i].age, &stu[i].num, stu[i].address);}//以二进制形式写文件FILE* fp = fopen("001.txt", "wb");if (fp == NULL){perror("open fail");exit(1);}for (int i = 0; i < 3; i++){if (fwrite(&stu[i], sizeof(info), 1, fp) != 1){perror("fwrite fail");exit(1);}}if (fclose(fp) == EOF){perror("close fail");exit(1);}//读二进制文件fp = fopen("001.txt", "rb");if (fp == NULL){perror("open fail");exit(1);}for (int i = 0; i < 3; i++){if (fread(&stu[i], sizeof(info), 1, fp) != 1){perror("fwrite fail");exit(1);}}for (int i = 0; i < 3; i++){printf("%s %d %d %s\n", stu[i].name, stu[i].age, stu[i].num, stu[i].address);}if (fclose(fp) == EOF){perror("close fail");exit(1);}return 0;
}

五、文件读写函数

5.1、fgetc与fputc

1. fgetc 函数​

​功能​

从指定的文件流(FILE*)中读取​​一个字符​​,并返回其ASCII值(int 类型)。如果到达文件末尾(EOF)或发生错误,返回 EOF(通常是 -1)。

原型​

int fgetc(FILE *stream);

参数​

  • stream:指向已打开的文件指针(如 stdin 或通过 fopen 打开的文件)。

​返回值​

  • 成功:返回读取的字符(转换为 int 类型)。
  • 失败/EOF:返回 EOF

示例​

#include <stdio.h>int main() {FILE *file = fopen("test.txt", "r");if (file == NULL) {perror("Error opening file");return 1;}int c;while ((c = fgetc(file)) != EOF) { // 逐字符读取直到文件末尾putchar(c); // 输出到屏幕}fclose(file);return 0;
}

注意事项​

  • 返回值是 int 而非 char,以便区分有效字符和 EOF
  • 文件必须已以​​读模式​​(如 "r")打开。

2. fputc 函数​

​功能​

向指定的文件流(FILE*)写入​​一个字符​​,返回写入的字符。失败时返回 EOF

原型​

int fputc(int char, FILE *stream);

参数​

  • char:要写入的字符(以 int 形式传递,实际写入低8位)。
  • stream:目标文件指针(如 stdout 或通过 fopen 打开的文件)。

​返回值​

  • 成功:返回写入的字符。
  • 失败:返回 EOF

示例​

#include <stdio.h>int main() {FILE *file = fopen("output.txt", "w");if (file == NULL) {perror("Error opening file");return 1;}char text[] = "Hello, world!";for (int i = 0; text[i] != '\0'; i++) {fputc(text[i], file); // 逐字符写入文件}fclose(file);return 0;
}

注意事项​

  • 文件必须已以​​写模式​​(如 "w""a")打开。
  • 可以配合 stdout 直接输出到屏幕

5.2、fgets与fputs

1. fgets 函数​

​功能​

从指定的文件流(FILE*)中读取​​一行字符串​​(或指定长度的字符),并存储到缓冲区中。读取时会保留换行符 \n(如果存在),并在末尾自动添加 \0(字符串结束符)。

原型​

char *fgets(char *str, int n, FILE *stream);

​参数​

  • str:指向存储读取数据的字符数组(缓冲区)。
  • n:最大读取字符数(包括 \0),通常设为缓冲区大小。
  • stream:文件指针(如 stdin 或 fopen 打开的文件)。

​返回值​

  • 成功:返回 str(即缓冲区地址)。
  • 失败:返回 NULL

​示例​

#include <stdio.h>int main() {FILE *file = fopen("test.txt", "r");if (file == NULL) {perror("Error opening file");return 1;}char buffer[100];while (fgets(buffer, sizeof(buffer), file) != NULL) { // 逐行读取printf("%s", buffer); // 输出到屏幕(包含换行符)}fclose(file);return 0;
}

注意事项​

  1. ​读取长度限制​​:fgets 最多读取 n-1 个字符(留一个位置给 \0)。
  2. ​换行符处理​​:
    • 如果遇到 \n,会将其存入缓冲区。
    • 如果缓冲区满(未遇到 \n),则不会自动添加换行符。
  3. stdin 输入​​:可以用 fgets(buffer, size, stdin) 替代 gets(避免缓冲区溢出)。

​2. fputs 函数​

​功能​

向指定的文件流(FILE*)写入一个​​字符串​​(不自动添加换行符 \n)。

​原型​

int fputs(const char *str, FILE *stream);

​参数​

  • str:要写入的字符串(必须以 \0 结尾)。
  • stream:目标文件指针(如 stdout 或 fopen 打开的文件)。

​返回值​

  • 成功:返回非负值(通常是 0 或写入的字符数)。
  • 失败:返回 EOF-1)。

​示例​

#include <stdio.h>int main() {FILE *file = fopen("output.txt", "w");if (file == NULL) {perror("Error opening file");return 1;}const char *text = "Hello, world!\n";fputs(text, file); // 写入文件(不自动添加 \n)fputs("Another line", file); // 继续写入(无换行)fclose(file);return 0;
}

​注意事项​

  1. ​不自动添加换行符​​:与 puts 不同,fputs 不会在末尾加 \n,需手动添加。
  2. stdout 输出​​:可以用 fputs(str, stdout) 替代 puts(但需自行处理换行)。
  3. ​安全性​​:相比 fprintffputs 更高效,适合写入已知字符串。

5.3、fprintf与fscanf

1. fprintf 函数​

​功能​

将格式化数据写入指定的文件流(如文本文件、标准输出等)。

​原型​

int fprintf(FILE *stream, const char *format, ...);
  • ​参数​​:
    • stream:目标文件流(如 stdout、文件指针等)。
    • format:格式化字符串(类似 printf)。
    • ...:可变参数,对应格式占位符的值。
  • ​返回值​​:成功时返回写入的字符数,失败时返回负数。

​示例

#include <stdio.h>int main() {FILE *file = fopen("output.txt", "w");if (file == NULL) {perror("Failed to open file");return 1;}int num = 42;fprintf(file, "Value: %d\n", num); // 写入文件fprintf(stdout, "Value: %d\n", num); // 等同于 printffclose(file);return 0;
}

2. fscanf 函数​

​功能​

从文件流中按指定格式读取数据(类似 scanf,但针对文件)。

​原型​

int fscanf(FILE *stream, const char *format, ...);
  • ​参数​​:
    • stream:源文件流(如 stdin、文件指针等)。
    • format:格式化字符串,定义如何解析输入。
    • ...:可变参数,用于存储读取结果的变量地址。
  • ​返回值​​:成功匹配并赋值的参数个数,失败或文件结束时返回 EOF

​示例

#include <stdio.h>int main() {FILE *file = fopen("input.txt", "r");if (file == NULL) {perror("Failed to open file");return 1;}int num;fscanf(file, "%d", &num); // 从文件读取整数printf("Read value: %d\n", num);fclose(file);return 0;
}

注意事项​

  1. ​文件操作必须检查返回值​​:
    • 使用 fopen 后需检查是否为 NULL
    • fscanf 在文件结束时返回 EOF,需处理错误情况。
  2. ​格式化字符串匹配​​:
    • fscanf 的格式占位符(如 %d%s)必须与输入数据严格匹配,否则可能导致读取失败。
  3. ​安全性​​:
    • fscanf 读取字符串时需避免缓冲区溢出(建议用 %Ns 指定最大长度,如 %99s)。
  4. ​二进制文件​​:
    • 对二进制数据,通常使用 fwrite/fread 而非 fprintf/fscanf

5.4、sprintf与sscanf

功能​

将​​格式化数据写入字符串缓冲区​​(将变量按指定格式转换为字符串)。

​原型

int sprintf(char *str, const char *format, ...);
  • ​参数​​:
    • str:目标字符串缓冲区(需提前分配足够内存)。
    • format:格式化字符串(与 printf 相同)。
    • ...:可变参数,对应格式占位符的值。
  • ​返回值​​:成功时返回写入的字符数(不包括 \0),失败时返回负数。

​示例

#include <stdio.h>int main() {char buffer[100];int num = 42;float pi = 3.14159;sprintf(buffer, "Number: %d, Pi: %.2f", num, pi);printf("Buffer: %s\n", buffer); // 输出: "Number: 42, Pi: 3.14"return 0;
}

2. sscanf 函数​

​功能​

从​​字符串中解析格式化数据​​(类似 scanf,但数据来源是字符串而非标准输入)。

​原型​

int sscanf(const char *str, const char *format, ...);
  • ​参数​​:
    • str:源字符串(包含待解析的数据)。
    • format:格式化字符串(定义如何解析数据)。
    • ...:可变参数,用于存储解析结果的变量地址。
  • ​返回值​​:成功匹配并赋值的参数个数,失败或无法匹配时返回 EOF

​示例

#include <stdio.h>int main() {char data[] = "John 25 3.5";char name[20];int age;float score;sscanf(data, "%s %d %f", name, &age, &score);printf("Name: %s, Age: %d, Score: %.1f\n", name, age, score);// 输出: "Name: John, Age: 25, Score: 3.5"return 0;
}

5.5、fread与fwrite

1. fwrite 函数​

​功能​

将内存中的数据块(如结构体、数组)​​直接写入文件​​,不进行任何格式转换(二进制写入)。

​原型​

size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
  • ​参数​​:
    • ptr:指向待写入数据的内存地址(如数组、结构体的指针)。
    • size:每个数据项的字节大小(如 sizeof(int))。
    • count:要写入的数据项数量。
    • stream:目标文件流(需以二进制模式打开,如 "wb")。
  • ​返回值​​:成功写入的数据项数量(非字节数),若小于 count 表示出错或文件结束。

​示例

#include <stdio.h>int main() {FILE *file = fopen("data.bin", "wb"); // 二进制写入模式if (!file) {perror("Failed to open file");return 1;}int nums[] = {1, 2, 3, 4, 5};size_t written = fwrite(nums, sizeof(int), 5, file);printf("Written %zu elements\n", written); // 应输出 5fclose(file);return 0;
}

2. fread 函数​

​功能​

从文件中​​直接读取二进制数据​​到内存,不进行格式解析(二进制读取)。

​原型

size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
  • ​参数​​:
    • ptr:存储读取数据的内存地址(需提前分配空间)。
    • size:每个数据项的字节大小(如 sizeof(float))。
    • count:要读取的数据项数量。
    • stream:源文件流(需以二进制模式打开,如 "rb")。
  • ​返回值​​:成功读取的数据项数量,若小于 count 表示出错或文件结束。

​示例

#include <stdio.h>int main() {FILE *file = fopen("data.bin", "rb"); // 二进制读取模式if (!file) {perror("Failed to open file");return 1;}int nums[5];size_t read = fread(nums, sizeof(int), 5, file);printf("Read %zu elements:\n", read);for (int i = 0; i < 5; i++) {printf("%d ", nums[i]); // 应输出 1 2 3 4 5}fclose(file);return 0;
}

5.6、总结

读取作用返回值异常判断
fgetc读字符intEOFstdin
fgets读字符串char*NULLstdin
scanf格式化读取intcountstdin
fscanf格式化读取intcountstdin
sscanf格式化读取(一般是数组)intcountstdin
fread二进制读取size_tcountstdin

注:fread的第二个参数是sizeof(数据类型),第三个参数是count

        qsort的第二个参数是count,第三个参数是sizeof(数据类型)

写入作用返回值异常判断
fputc写字符intEOFstdout
fputs写字符串intEOFstdout
printf格式化写入intcountstdout
fprintf格式化写入intcountstdout
sprintf格式化写入(一般是数组)intcountstdout
fwrite二进制写入size_tcountstdout

 注:fwrite的第二个参数是sizeof(数据类型),第三个参数是count

六、文件的随机读取

 6.1、rewind函数

功能​

将文件指针​​重置到文件开头​​,相当于 fseek(fp, 0, SEEK_SET) 的简化版。

​原型

void rewind(FILE *stream);
  • ​参数​​:

    • stream:目标文件流。
  • ​返回值​​:无(不返回错误信息,如需检查错误需调用 ferror

示例​

FILE *fp = fopen("test.txt", "r");
if (fp == NULL) {perror("Failed to open file");return 1;
}// 读取文件内容后,重置指针到开头
char buffer[100];
fgets(buffer, sizeof(buffer), fp);
printf("First line: %s", buffer);rewind(fp); // 回到文件开头
fgets(buffer, sizeof(buffer), fp);
printf("First line again: %s", buffer);fclose(fp);

6.2、fseek 函数​

​功能​

将文件指针​​移动到指定位置​​,支持从文件头、当前位置或文件尾偏移。

​原型

int fseek(FILE *stream, long offset, int whence);
  • ​参数​​:
    • stream:目标文件流。
    • offset:偏移量(字节数,可正可负)。
    • whence:基准位置,取以下值之一:
      • SEEK_SET(文件开头)
      • SEEK_CUR(当前位置)
      • SEEK_END(文件末尾)
  • ​返回值​​:成功返回 0,失败返回非零值(需用 ferror 检查错误)

示例​

FILE *fp = fopen("data.bin", "rb");
if (fp == NULL) {perror("Failed to open file");return 1;
}// 跳过前 10 字节
fseek(fp, 10, SEEK_SET);// 从当前位置向后移动 5 字节
fseek(fp, 5, SEEK_CUR);// 定位到文件末尾前 20 字节
fseek(fp, -20, SEEK_END);fclose(fp);

6.3、ftell 函数​

​功能​

返回文件指针的​​当前位置​​(相对于文件开头的字节偏移量)。

​原型

long int ftell(FILE *stream);
  • ​参数​​:
    • stream:目标文件流。
  • ​返回值​​:当前偏移量(字节数),失败返回 -1L

​示例

FILE *fp = fopen("test.txt", "r");
if (fp == NULL) {perror("Failed to open file");return 1;
}fseek(fp, 0, SEEK_END); // 跳到文件末尾
long size = ftell(fp);  // 获取文件大小
printf("File size: %ld bytes\n", size);rewind(fp); // 重置指针
printf("Current position after rewind: %ld\n", ftell(fp)); // 输出 0fclose(fp);

七、文件读取结束的判定

7.1、feof函数

功能​

检测文件流是否已经到达​​文件末尾(End Of File, EOF)​​。

​原型

int feof(FILE *stream);
  • ​参数​​:
    • stream:要检测的文件流。
  • ​返回值​​:
    • ​非零值(true)​​:已到达文件末尾。
    • ​0(false)​​:未到达文件末尾。

​使用场景​

  • 在循环读取文件时判断是否读完所有数据。
  • ​注意​​:feof 只有在尝试读取​​超出文件末尾​​时才会返回 true,因此不能单独用它来控制循环(否则可能导致多读一次)。

​示例

#include <stdio.h>int main() {FILE *fp = fopen("test.txt", "r");if (fp == NULL) {perror("Failed to open file");return 1;}char buffer[100];while (fgets(buffer, sizeof(buffer), fp) != NULL) {printf("%s", buffer);}if (feof(fp)) {printf("\nReached end of file.\n");} else if (ferror(fp)) {printf("\nError while reading file.\n");}fclose(fp);return 0;
}

说明​​:

  • 使用 fgets 读取文件,直到返回 NULL(表示可能到达文件末尾或发生错误)。
  • 再用 feof 确认是否真的到达文件末尾,而不是因为错误

7.2、ferror函数

检测文件流是否发生了​​读写错误​​(如磁盘损坏、权限不足等)。

​原型

int ferror(FILE *stream);
  • ​参数​​:
    • stream:要检测的文件流。
  • ​返回值​​:
    • ​非零值(true)​​:发生了错误。
    • ​0(false)​​:无错误。

​使用场景​

  • 在文件操作后检查是否出错(如 freadfwritefscanf 等)。
  • 结合 clearerr 可以清除错误标志(见下文)。

​示例​

#include <stdio.h>int main() {FILE *fp = fopen("test.txt", "r");if (fp == NULL) {perror("Failed to open file");return 1;}// 尝试读取一个不存在的字符(触发错误)int ch = fgetc(fp);if (ch == EOF) {if (feof(fp)) {printf("Reached EOF.\n");} else if (ferror(fp)) {printf("Error while reading file.\n");clearerr(fp); // 清除错误标志}}fclose(fp);return 0;
}

说明​​:

  • 如果 fgetc 返回 EOF,可能是文件结束或发生错误。
  • 用 ferror 判断是否是错误导致,并用 clearerr 清除错误标志(以便后续操作)
http://www.xdnf.cn/news/641143.html

相关文章:

  • 12.LCD、FSMC和ILI9341芯片
  • python中pandas之dataframe知识
  • 文本存入向量数据库流程
  • Python海龟绘图(turtle模块)常考知识点总结
  • 【数据结构】线性表之“双链表(带头循环双向链表)”
  • java 加密算法的简单使用
  • Linux系统中实时查看日志
  • Unity3D仿星露谷物语开发50之初始化农作物
  • day27:零基础学嵌入式之进程
  • Docker镜像存储路径迁移指南(解决磁盘空间不足问题)
  • Nginx安全防护
  • 基于Python Anaconda环境,使用CNN-LSTM模型预测碳交易价格的完整技术方案
  • 大模型与训练与微调
  • Java基础 Day20
  • 嵌入式自学第二十七天
  • ST表——算法的优化
  • TCP 和 UDP 的区别
  • 电梯调度算法详解与Python实现
  • 页表:从虚拟内存到物理内存的转换
  • C语言初阶--操作符
  • 消息队列kafka的基础概念和部署
  • C#、C++、Java、Python 选择哪个好
  • TCP 的三次握手
  • Python Day32 学习
  • 十二、【鸿蒙 NEXT】如何使用系统api实现视频压缩
  • 电子电路:电学都有哪些核心概念?
  • Oracle控制文件损坏恢复方案
  • dify_plugin数据库中的表总结
  • threejs几何体BufferGeometry顶点
  • 【报错】Error attempting to get column ‘created_time‘ from result set.解决方法