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

《零基础学 C 语言文件顺序读写:fputc/fgetc 到 fread/fwrite 函数详解》

目录

1. fputc函数和fgetc函数

fputc函数

fgetc函数

2. feof和ferror函数

feof 函数

ferror 函数

3.   fputs函数和fgets函数

fputs 函数

fgets 函数

4.  fprintf函数和fscanf函数

fprintf 函数

fscanf 函数

5. fread函数和fwrite函数

fwrite 函数

fread 函数


1. fputc函数和fgetc函数

fputc函数

在 C 语言中,fputc 函数用于向指定的文件流写入单个字符,是文件字符输出的基础函数。

函数原型

#include <stdio.h>
int fputc(int character, FILE *stream);

参数说明

  • character:要写入的字符(虽然声明为 int,但实际只使用低 8 位,即 char 范围)。

  • stream:文件指针(FILE* 类型),指定写入的目标流(如文件流、标准输出流 stdout 等)。

返回值

  • 成功:返回写入的字符(以 int 类型表示)。

  • 失败:返回 EOF(通常为 -1,表示写入错误或文件结束)。

基本用法

1. 向文件写入字符

#include <stdio.h>int main() {FILE *fp = fopen("test.txt", "w");  // 以只写模式打开文件if (fp == NULL) {perror("文件打开失败");return 1;}// 写入单个字符fputc('A', fp);       // 写入字符 'A'fputc('\n', fp);      // 写入换行符fputc('B', fp);       // 写入字符 'B'fclose(fp);return 0;
}

运行后,test.txt 文件内容为:

A
B

2. 向标准输出流(屏幕)写入字符

fputc 也可用于标准流,例如向屏幕输出:

#include <stdio.h>int main() {// 向 stdout(屏幕)输出字符,等价于 putchar('H')fputc('H', stdout);fputc('i', stdout);fputc('\n', stdout);  // 输出换行return 0;
}

运行后屏幕输出:

Hi

特点与注意事项

  1. 逐个字符写入fputc 每次只能写一个字符,适合处理文本文件的逐字符输出。

  2. 缓冲机制:写入文件时,数据会先存入缓冲区,缓冲区满或调用 fclose/fflush 时才会真正写入磁盘。

  3. 与 putchar 的关系putchar(c) 本质是 fputc(c, stdout) 的宏定义,专门用于向屏幕输出单个字符。

  4. 错误处理:需检查返回值是否为 EOF 以判断写入是否成功,例如:

    if (fputc('C', fp) == EOF) {perror("写入失败");
    }
    

  5. 二进制文件适用fputc 同样可用于二进制文件(打开模式带 b),直接写入字符的 ASCII 码值(原始字节)。

fgetc函数

在 C 语言中,fgetc 函数用于从指定的文件流中读取一个字符,是进行文件字符输入操作的常用函数。

函数原型

#include <stdio.h>
int fgetc(FILE *stream);

参数说明

stream:文件指针(FILE* 类型),指向要从中读取字符的文件流。可以是通过 fopen 函数打开的文件流,也可以是标准输入流 stdin 等。

返回值

  • 成功:返回读取到的字符(以 int 类型表示,实际使用低 8 位来存储字符的 ASCII 码值 )。
  • 失败或到达文件末尾:返回 EOF(通常被定义为 -1 )。

基本用法示例

1. 从文件中读取字符

#include <stdio.h>int main() {FILE *fp = fopen("test.txt", "r");if (fp == NULL) {perror("文件打开失败");return 1;}int ch;while ((ch = fgetc(fp)) != EOF) {putchar(ch);  // 将读取到的字符输出到屏幕}fclose(fp);return 0;
}

上述代码中,先以只读模式打开 test.txt 文件,然后使用 fgetc 函数循环读取文件中的字符,直到读取到文件末尾(返回 EOF ),并通过 putchar 函数将读取到的字符逐个输出到屏幕上。

2. 从标准输入流(键盘)读取字符

#include <stdio.h>int main() {int ch;printf("请输入一些字符,按 Ctrl+Z(Windows)或 Ctrl+D(Linux/macOS)结束输入:\n");while ((ch = fgetc(stdin)) != EOF) {putchar(ch);}return 0;
}

这段代码通过 fgetc 从标准输入流 stdin 中读取用户从键盘输入的字符,并将其输出到屏幕上。在 Windows 系统中,用户按下 Ctrl+Z 再按回车键表示输入结束;在 Linux 和 macOS 系统中,按下 Ctrl+D 表示输入结束。

注意事项

1.错误判断:在使用 fgetc 读取字符后,一定要检查返回值是否为 EOF ,以此判断是读取到文件末尾还是发生了读取错误。

2.类型转换:虽然 fgetc 的返回值是 int 类型,但在将返回值赋值给 char 类型变量时,需要进行合适的类型转换,并且要注意处理 EOF 的情况,避免误将 EOF 当作普通字符处理。

3.缓冲区影响:文件流存在缓冲区,fgetc 读取字符时,先从缓冲区获取数据。当缓冲区为空时,才会真正从磁盘文件中读取数据填充缓冲区。

4.二进制文件读取fgetc 也可以用于读取二进制文件,但由于 EOF 也是一个合法的返回值,所以在读取二进制文件时,不能单纯通过判断返回值是否为 EOF 来判断读取是否结束,通常需要结合文件大小等其他信息来判断。

2. feof和ferror函数

在 C 语言文件操作中,feofferror是用于判断文件操作状态的两个重要函数,前者主要用于检测文件是否到达结尾,后者用于判断文件操作过程中是否出现错误,以下是详细介绍:

feof 函数

  • 函数原型

#include <stdio.h>
int feof(FILE *stream);
  • 参数说明stream是一个文件指针,指向要检测状态的文件流,这个文件流通常是通过fopen函数打开文件后返回的指针。

  • 返回值

    • 文件未到达结尾:函数返回 0。

    • 文件到达结尾:函数返回一个非零值(通常是 1)。

  • 使用场景及示例
    在使用循环从文件中读取数据时,判断是否读取到文件末尾。

#include <stdio.h>int main() {FILE *fp = fopen("test.txt", "r");if (fp == NULL) {perror("文件打开失败");return 1;}int ch;while (!feof(fp)) {ch = fgetc(fp);putchar(ch);}fclose(fp);return 0;
}

上述代码中,通过feof函数判断是否到达文件末尾,若未到达则继续读取字符并输出。但需要注意,feof函数是在读取操作后才更新文件结束标志,因此在读取文件时,不能单纯依赖feof函数作为循环读取的条件,因为可能会多读一次,更好的做法是先读取,再判断返回值是否为EOF,如:

#include <stdio.h>int main() {FILE *fp = fopen("test.txt", "r");if (fp == NULL) {perror("文件打开失败");return 1;}int ch;while ((ch = fgetc(fp)) != EOF) {putchar(ch);}fclose(fp);return 0;
}

ferror 函数

  • 函数原型

#include <stdio.h>
int ferror(FILE *stream);
  • 参数说明stream同样是一个文件指针,指向要检测状态的文件流。

  • 返回值

    • 文件操作未出错:函数返回 0。

    • 文件操作出现错误:函数返回一个非零值(通常是 1)。

  • 使用场景及示例
    在对文件进行读写操作后,判断是否出现错误。

#include <stdio.h>int main() {FILE *fp = fopen("test.txt", "w");if (fp == NULL) {perror("文件打开失败");return 1;}if (fputs("Hello, world!", fp) == EOF) {if (ferror(fp)) {perror("写入文件时出错");}}fclose(fp);return 0;
}

上述代码中,在使用fputs向文件写入数据后,判断返回值是否为EOF,若为EOF则调用ferror函数判断是否是因为写入错误导致的,若是则输出错误信息。

注意事项

  • feof函数:不能在未进行读取操作前就用它判断文件是否结束,要结合实际读取操作和返回值判断。

  • ferror函数:它检测的是最近一次文件操作是否出错,在进行新的文件操作前,需要根据需要进行错误处理,例如可以使用clearerr函数清除错误标志,以便后续正确检测文件操作状态。

clearerr(fp); // 清除文件流fp的错误和文件结束标志

3.   fputs函数和fgets函数

在 C 语言中,fputs 和 fgets 是用于字符串级文件读写的标准库函数,分别用于向文件流写入字符串和从文件流读取字符串,比单字符操作的 fputc/fgetc 更高效。

fputs 函数

向文件流写入字符串

函数原型

#include <stdio.h>
int fputs(const char *str, FILE *stream);

参数说明

  • str:要写入的字符串(以 \0 结尾的字符数组)。

  • stream:目标文件流(如文件指针、stdout 等)。

返回值

  • 成功:返回非负值(通常为非零)。

  • 失败:返回 EOF-1)。

特点与用法

  1. 写入规则
    只写入字符串中的有效字符(从首字符到 \0 前的字符),不自动添加换行符,也不写入 \0 本身。

  2. 示例 1:向文件写入字符串

    #include <stdio.h>int main() {FILE *fp = fopen("test.txt", "w");if (fp == NULL) {perror("文件打开失败");return 1;}// 写入字符串(需手动添加换行符)fputs("Hello, fputs!", fp);fputs("\n这是第二行", fp);  // 手动加 '\n' 换行fclose(fp);return 0;
    }
    

    结果(test.txt):

    Hello, fputs!
    这是第二行
    
  3. 示例 2:向标准输出流(屏幕)写入
    等价于 puts 但不自动换行:

    fputs("Hello, stdout!", stdout);  // 输出到屏幕,无换行
    fputs("\n", stdout);              // 手动换行
    

fgets 函数

从文件流读取字符串

函数原型

#include <stdio.h>
char *fgets(char *str, int size, FILE *stream);

参数说明

  • str:用于存储读取结果的字符数组。

  • size:最大读取长度(包含结尾的 \0,实际最多读 size-1 个字符)。

  • stream:源文件流(如文件指针、stdin 等)。

返回值

  • 成功:返回 str(读取到的字符串的地址)。

  • 失败或文件结束:返回 NULL

特点与用法

  1. 读取规则

    • 最多读取 size-1 个字符,或遇到换行符 \n 时停止(会保留换行符)。

    • 读取结束后自动在末尾添加 \0,确保字符串完整。

  2. 示例 1:从文件读取字符串

    #include <stdio.h>int main() {FILE *fp = fopen("test.txt", "r");if (fp == NULL) {perror("文件打开失败");return 1;}char buffer[100];// 循环读取,直到文件结束while (fgets(buffer, 100, fp) != NULL) {printf("读取到:%s", buffer);  // buffer 已包含换行符}fclose(fp);return 0;
    }
    

    若 test.txt 内容为:

    第一行内容
    第二行内容
    

    输出结果:

    读取到:第一行内容
    读取到:第二行内容
    
  3. 示例 2:从标准输入流(键盘)读取
    可读取一行输入(含空格):

    char input[50];
    printf("请输入一行文字:");
    fgets(input, 50, stdin);  // 读取键盘输入,最多49个字符
    printf("你输入了:%s", input);
    

三、注意事项

  1. fputs 的坑点

    • 不会自动添加换行符,需手动写入 \n

    • 若字符串中包含 \0(如二进制数据),会提前终止写入(只写 \0 前的内容)。

  2. fgets 的坑点

    • 若一行内容超过 size-1,会截断读取(剩余内容留在流中,下次读取继续)。

    • 会保留换行符 \n,如需去除可手动处理:

// 去除 fgets 读取的换行符
char buffer[100];
fgets(buffer, 100, fp);
buffer[strcspn(buffer, "\n")] = '\0';  // 用 \0 替换 \n

读取到文件末尾或错误时返回 NULL,需结合 feof/ferror 判断原因。

  1. 与 puts/gets 的区别

    • puts(str) 等价于 fputs(str, stdout) + fputs("\n", stdout)(自动换行)。

    • gets 因无长度限制存在缓冲区溢出风险,已被弃用,推荐用 fgets 替代。

4.  fprintf函数和fscanf函数

在 C 语言中,fprintf函数和fscanf函数是用于格式化输入输出的函数,和标准输入输出函数printfscanf 功能类似,区别在于fprintffscanf操作的是文件流,可以实现向文件中进行格式化写入以及从文件中格式化读取数据。

fprintf 函数

fprintf函数用于向指定的文件流中按照指定的格式写入数据。

函数原型

#include <stdio.h>
int fprintf(FILE *stream, const char *format, ...);

参数说明

  • stream:指向要写入数据的文件流,可以是通过fopen函数打开的文件指针,也可以是标准输出流stdout(表示输出到屏幕)、标准错误流stderr 。

  • format:格式化字符串,用于指定输出数据的格式,包含普通字符、转义字符以及格式说明符,如%d(表示整数)、%f(表示浮点数)、%s(表示字符串)等。

  • ...:可变参数列表,根据format中格式说明符的数量和类型,传入相应的要输出的数据。

返回值

  • 成功:返回实际写入的字符个数。

  • 失败:返回一个负数。

示例代码

#include <stdio.h>int main() {FILE *fp = fopen("test.txt", "w");if (fp == NULL) {perror("文件打开失败");return 1;}int num = 10;float fnum = 3.14;char str[] = "Hello";// 向文件中格式化写入数据int written_count = fprintf(fp, "整数: %d, 浮点数: %f, 字符串: %s\n", num, fnum, str);if (written_count < 0) {perror("写入失败");}fclose(fp);return 0;
}

上述代码以写入模式打开文件test.txt,然后使用fprintf将整数、浮点数和字符串按照指定格式写入文件中,最后关闭文件。

fscanf 函数

fscanf函数用于从指定的文件流中按照指定的格式读取数据。

函数原型

#include <stdio.h>
int fscanf(FILE *stream, const char *format, ...);

参数说明

  • stream:指向要读取数据的文件流,通常是通过fopen函数打开的文件指针,也可以是标准输入流stdin(表示从键盘读取)。

  • format:格式化字符串,用于指定读取数据的格式,与fprintf中的format类似,包含格式说明符等。

  • ...:可变参数列表,是指向用于存储读取数据的变量的指针,参数的数量和类型要与format中的格式说明符相匹配。

返回值

  • 成功:返回成功匹配和赋值的输入项的个数。

  • 失败:返回EOF(通常为-1)。

示例代码

#include <stdio.h>int main() {FILE *fp = fopen("test.txt", "r");if (fp == NULL) {perror("文件打开失败");return 1;}int num;float fnum;char str[20];// 从文件中格式化读取数据int read_count = fscanf(fp, "整数: %d, 浮点数: %f, 字符串: %s", &num, &fnum, str);if (read_count == EOF) {perror("读取失败");} else {printf("读取到的数据:整数: %d, 浮点数: %f, 字符串: %s\n", num, fnum, str);}fclose(fp);return 0;
}

上述代码以读取模式打开文件test.txt,然后使用fscanf按照指定格式从文件中读取整数、浮点数和字符串,根据读取结果进行相应处理,最后关闭文件。

注意事项

  • 文件打开模式:使用fprintf写入文件时,文件需以写模式(如"w""w+"等)打开;使用fscanf读取文件时,文件需以读模式(如"r""r+"等)打开。

  • 格式匹配fprintffscanfformat里的格式说明符要与实际数据类型严格匹配,否则可能导致写入或读取的数据不正确,甚至程序崩溃。

  • 缓冲区影响:文件流存在缓冲区机制,读写操作可能不会立即反映到文件中,在合适的时候(如关闭文件前)可以使用fflush函数刷新缓冲区,确保数据正确写入文件。

  • 错误处理:要根据函数的返回值及时判断操作是否成功,并进行相应的错误处理,以增强程序的健壮性。

5. fread函数和fwrite函数

在 C 语言中,fread 和 fwrite 是用于二进制文件读写的核心函数,支持对任意数据类型(如结构体、数组等)进行块级读写,比字符 / 字符串级函数(如 fputc/fgets)更高效,尤其适合处理二进制数据(如图片、音频、自定义结构体等)。

fwrite 函数

向文件流写入二进制数据

函数原型

#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);

参数说明

  • ptr:指向要写入数据的内存地址(源数据的起始地址)。

  • size单个数据单元的字节大小(如 sizeof(int) 表示每个 int 占 4 字节)。

  • count:要写入的数据单元数量(如写入 3 个 int,则 count=3)。

  • stream:目标文件流(需以二进制模式打开,如 "wb"/"ab" 等)。

返回值

  • 成功:返回实际写入的数据单元数量(小于等于 count)。

  • 失败 / 写入不完整:返回值小于 count(需结合 ferror 判断错误)。

特点与用法

  1. 二进制写入:直接按内存中的原始字节写入,不进行任何格式转换(如不转换换行符),适合非文本数据。

  2. 批量操作:一次可写入多个数据单元(如数组、结构体数组),效率高。

示例 1:写入单个结构体

#include <stdio.h>// 定义一个结构体
typedef struct {int id;char name[20];float score;
} Student;int main() {FILE *fp = fopen("students.dat", "wb");  // 二进制写模式if (fp == NULL) {perror("文件打开失败");return 1;}Student s = {101, "ZhangSan", 95.5f};// 写入1个Student类型数据(每个占sizeof(Student)字节)size_t written = fwrite(&s, sizeof(Student), 1, fp);if (written != 1) {perror("写入失败");}fclose(fp);return 0;
}

示例 2:写入数组

// 写入一个int数组
int nums[] = {1, 2, 3, 4, 5};
int len = sizeof(nums) / sizeof(nums[0]);
// 写入5个int(每个4字节)
fwrite(nums, sizeof(int), len, fp);

fread 函数

从文件流读取二进制数据

函数原型

#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t count, FILE *stream);

参数说明

  • ptr:指向用于存储读取数据的内存地址(目标缓冲区)。

  • size:单个数据单元的字节大小(同 fwrite)。

  • count:计划读取的数据单元数量。

  • stream:源文件流(需以二进制读模式打开,如 "rb"/"rb+" 等)。

返回值

  • 成功:返回实际读取的数据单元数量(等于 count 表示读满,小于 count 可能是文件结束或出错)。

  • 失败:返回 0(需结合 feof/ferror 判断是文件结束还是错误)。

特点与用法

  1. 二进制读取:按原始字节读取,与写入时的内存布局完全一致,确保数据完整还原。

  2. 精准还原:可直接读取结构体、数组等复杂类型,无需手动解析格式。

示例:读取之前写入的结构体

#include <stdio.h>typedef struct {int id;char name[20];float score;
} Student;int main() {FILE *fp = fopen("students.dat", "rb");  // 二进制读模式if (fp == NULL) {perror("文件打开失败");return 1;}Student s;// 读取1个Student类型数据size_t read = fread(&s, sizeof(Student), 1, fp);if (read == 1) {// 成功读取,打印数据printf("ID: %d, Name: %s, Score: %.1f\n", s.id, s.name, s.score);} else if (feof(fp)) {printf("已到达文件末尾\n");} else if (ferror(fp)) {perror("读取失败");}fclose(fp);return 0;
}

三、关键注意事项

  1. 必须用二进制模式打开文件
    读写时需指定 b 模式(如 "wb"/"rb"),否则在 Windows 系统中可能因换行符转换破坏二进制数据。

  2. 数据一致性
    写入和读取时的 size 和数据类型必须完全一致(如写入 sizeof(Student),读取也必须用 sizeof(Student)),否则会导致数据解析错误。

  3. 返回值判断

    • 不能仅通过返回值是否为 0 判断失败(可能是文件结束),需用 feof 区分 “文件结束” 和 “读取错误”。

    • 示例:
      size_t n = fread(buf, size, count, fp);
      if (n < count) {if (feof(fp)) {// 正常结束:已读到文件末尾} else if (ferror(fp)) {// 读取错误}
      }
      

  4. 跨平台兼容性
    结构体在不同编译器 / 平台可能有字节对齐差异,如需跨平台传输,需手动处理对齐(如用 #pragma pack)。

  5. 与文本函数的区别

    • fwrite/fread 适合二进制数据(图片、音频、结构体等),按字节精准操作。

    • fprintf/fscanf 适合文本数据,会进行格式转换(如整数转字符串)。

http://www.dtcms.com/a/350300.html

相关文章:

  • 并行算法与向量化指令集的实战经验
  • 【Linux内核实时】实时互斥锁 - sched_rt_mutex
  • 寂静之歌 单机+联机(Songs Of Silence)免安装中文版
  • 数据存储的思考——从RocketMQ和Mysql的架构入手
  • 力扣498 对角线遍历
  • Qwen2-Plus与DeepSeek-V3深度测评:从API成本到场景适配的全面解析
  • 消费场景的构建来自哪些方面?
  • KEPServerEX——工业数据采集与通信的标准化平台
  • 处理端口和 IP 地址
  • 最新刀客IP地址信息查询系统源码_含API接口_首发
  • AI被干冒烟了
  • HTML+CSS+JavaScript实现的AES加密工具网页应用,包含完整的UI界面和加密/解密功能
  • 系统开发 Day4
  • idea官网选择具体版本的下载步骤
  • 解决VSCode终端中文乱码问题
  • Cursor入门
  • Node.js面试题及详细答案120题(43-55) -- 性能优化与内存管理篇
  • HarmonyOS 中的 @Prop:深入理解单向数据传递机制
  • Java多态大冒险:当动物们开始“造反”
  • K8s高可用:Master与候选节点核心解析
  • STM32高级定时器-输出比较模式
  • 基于周期因子的资金流入流出预测
  • 区间和使用前缀和方法得到的时间复杂度
  • 2025 高教社杯全国大学生数学建模竞赛A题B题C题D题E题思路+模型+代码+论文(9.4开赛后第一时间更新)
  • AD画PCB时不小心移除的焊盘如何恢复
  • 玩转ChatGPT:Kimi深度研究功能
  • 模拟IC设计基础系列10-virtuoso常用快捷键整理(基础操作)
  • 驱动清理工具Driver Store Explorer(驱动程序资源管理器) 中文便携版
  • 重学前端010 --- 响应式网页设计 中级CSS
  • 【C++ 11 新特性】function 函数包装器的使用