c语言文件操作(中)

五、文件顺序读写(从头依次读写)

1. 读写函数总表

函数作用适用范围
fgetc读取单个字符所有输入流(文件 /stdin)
fputc写入单个字符所有输出流(文件 /stdout)
fgets读取一行字符串所有输入流
fputs写入一行字符串所有输出流
fscanf格式化读取所有输入流
fprintf格式化写入所有输出流
fread二进制批量读仅文件输入流
fwrite二进制批量写仅文件输出流

fgetc 详细用法

1. 功能

从已打开的文件流中读取1 个字符,读取完成后,文件内部的位置指针会自动向后移动 1 字节。 

2. 函数原型
int fgetc(FILE *stream);
  • 参数 stream:已经打开的文件指针(即 fopen 返回的 FILE*)。
  • 返回值:
    • 成功:返回读取到的字符的 ASCII 码值(int 类型)
    • 读到文件末尾 / 读取失败:返回 EOF(标准宏,值通常为 -1

为什么返回 int 而不是 char? 若 char 是无符号类型,EOF(-1) 无法用 char 正确表示;用 int 可以兼容所有字符 + 错误 / 末尾标记。

3. 典型用法:遍历读取整个文件
int ch; // 必须用int接收,不能用char
while ((ch = fgetc(pf)) != EOF)
{
    printf("%c", ch); // 打印读到的字符
}

fputc 详细用法

1. 功能

将 1 个字符写入到已打开的文件流中,写入完成后,文件内部位置指针自动向后移动 1 字节。 

2. 函数原型
int fputc(int character, FILE *stream);
  • 参数 1 character:要写入的字符(传 char 类型会自动提升为 int
  • 参数 2 stream:目标文件指针。
  • 返回值:
    • 成功:返回写入的字符本身
    • 失败:返回 EOF
3. 典型用法:逐个写入字符
// 文件必须以写模式打开,如 "w" / "a"
fputc('a', pf);  // 写入字符 'a'
fputc('\n', pf); // 写入换行符

四、示例

示例 1:用 fgetc 读取文件并打印
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
    FILE* pf = fopen("C:/Users/Edbsee/Desktop/test.txt", "r");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    int ch;
    while ((ch = fgetc(pf)) != EOF)
    {
        printf("%c", ch);
    }

    fclose(pf);
    pf = NULL;
    return 0;
}
示例 2:用 fputc 写入文件
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
    // w模式:文件不存在则创建,存在则清空原有内容
    FILE* pf = fopen("C:/Users/Edbsee/Desktop/test.txt", "w");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    char str[] = "hello world";
    for (int i = 0; str[i] != '\0'; i++)
    {
        fputc(str[i], pf);
    }

    fclose(pf);
    pf = NULL;
    printf("写入完成\n");
    return 0;
}

fgets 详细用法

1. 功能

从指定文件流中读取一行字符,存入字符数组,遇到换行符 \n 或读满最大字符数 - 1 时停止,并自动在字符串末尾追加结束符 \0

注意:读取到的换行符 \n 会被一并存入字符串中,不会被丢弃。

2. 函数原型
char *fgets(char *str, int num, FILE *stream);
  • 参数:
    • str:目标字符数组的首地址,用于存放读取到的字符串
    • num:最多读取的字符总数(包含末尾自动添加的 \0,因此实际最多读取 num-1 个有效字符)
    • stream:已打开的文件指针
  • 返回值:
    • 读取成功:返回字符数组 str 的首地址
    • 读到文件末尾 / 读取失败:返回 NULL
3. 典型用法:逐行读取整个文件
char buf[1024]; // 存放一行内容的缓冲区
while (fgets(buf, sizeof(buf), pf) != NULL)
{
    printf("%s", buf); // 直接打印,因为buf里自带换行符
}

fputs 详细用法

1. 功能

将一个字符串写入指定文件流,只写入字符串内容(到 \0 为止,\0 本身不写入),不会自动添加换行符

2. 函数原型
int fputs(const char *str, FILE *stream);
  • 参数:
    • str:要写入的字符串首地址
    • stream:目标文件指针
  • 返回值:
    • 写入成功:返回非负整数
    • 写入失败:返回 EOF
3. 典型用法:写入一行内容
fputs("hello world\n", pf); // 要换行必须手动加 \n
fputs("第二行内容\n", pf);

四、示例

示例 1:用 fgets 逐行读取文件
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
    FILE* pf = fopen("C:/Users/Edbsee/Desktop/test.txt", "r");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    char buf[1024]; // 一行最多读1023个字符 + 1个\0
    while (fgets(buf, sizeof(buf), pf) != NULL)
    {
        printf("%s", buf);
    }

    fclose(pf);
    pf = NULL;
    return 0;
}
示例 2:用 fputs 写入多行到文件
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
    FILE* pf = fopen("C:/Users/Edbsee/Desktop/test.txt", "w");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    fputs("第一行:C语言文件操作\n", pf);
    fputs("第二行:fputs函数演示\n", pf);
    fputs("第三行:手动加换行符\n", pf);

    fclose(pf);
    pf = NULL;
    printf("写入完成\n");
    return 0;
}

fprintf 详细用法

1. 功能

按照指定的格式字符串,将数据格式化后写入目标文件流。用法和 printf 完全一致,仅多了第一个文件指针参数。 fprintf(stdout, ...) 等价于 printf(...),可直接输出到屏幕。

2. 函数原型
int fprintf(FILE *stream, const char *format, ...);
  • 参数:
    • stream:已打开的目标文件指针
    • format:格式控制字符串,和 printf 的格式符完全通用(%d %s %f %c 等)
    • ...:可变参数列表,对应格式符的待写入数据
  • 返回值:
    • 成功:返回实际写入的字符总数
    • 失败:返回负值
3. 典型用法
// 写入字符串、整数、浮点数
fprintf(pf, "姓名:%s 年龄:%d 成绩:%.2f\n", "张三", 20, 95.5);

fscanf 详细用法

1. 功能

从文件流中按照指定格式读取数据,并存入对应的变量地址中。用法和 scanf 完全一致,仅多了第一个文件指针参数。 fscanf(stdin, ...) 等价于 scanf(...),可从键盘读取输入。

2. 函数原型
int fscanf(FILE *stream, const char *format, ...);
  • 参数:
    • stream:已打开的源文件指针
    • format:格式控制字符串,和 scanf 格式符通用
    • ...:可变参数列表,对应格式符的变量地址(必须传地址)
  • 返回值:
    • 成功:返回成功匹配并赋值的参数个数
    • 读到文件末尾 / 读取失败:返回 EOF
3. 典型用法
char name[20];
int age;
float score;
// 按格式读取,变量必须传地址
fscanf(pf, "姓名:%s 年龄:%d 成绩:%f", name, &age, &score);

四、示例

示例 1:用 fprintf 写入结构化数据
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
    FILE* pf = fopen("C:/Users/Edbsee/Desktop/student.txt", "w");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    // 写入3条学生信息,每条占一行
    fprintf(pf, "%s %d %.1f\n", "张三", 20, 95.5);
    fprintf(pf, "%s %d %.1f\n", "李四", 19, 88.0);
    fprintf(pf, "%s %d %.1f\n", "王五", 21, 92.5);

    fclose(pf);
    pf = NULL;
    printf("写入完成\n");
    return 0;
}
示例 2:用 fscanf 读取结构化数据
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
    FILE* pf = fopen("C:/Users/Edbsee/Desktop/student.txt", "r");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    char name[20];
    int age;
    float score;

    // 循环读取,直到文件末尾
    while (fscanf(pf, "%s %d %f", name, &age, &score) != EOF)
    {
        printf("姓名:%s,年龄:%d,成绩:%.1f\n", name, age, score);
    }

    fclose(pf);
    pf = NULL;
    return 0;
}

fwrite 详细用法

1. 功能

把内存中一块连续的二进制数据,按字节原样写入文件流,不做任何格式转换。参数是 void* 类型,支持任意数据类型的写入。

2. 函数原型
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
  • 参数:
    • ptr:待写入数据的内存起始地址(数组、结构体变量地址等)
    • size:单个数据块的字节大小
    • count:要写入的数据块总个数
    • stream:目标文件指针
  • 返回值:实际成功写入的完整数据块个数(不是字节数)。正常情况下等于 count;若返回值小于 count,说明写入出错或磁盘空间不足。
3. 典型用法
int arr[] = {1, 2, 3, 4, 5};
// 写入5个int型数据,每个数据大小为 sizeof(int)
fwrite(arr, sizeof(int), 5, pf);

fread 详细用法

1. 功能

从文件中读取连续的字节数据,原样存入内存缓冲区,不做格式解析。

2. 函数原型
size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
  • 参数:
    • ptr:存放读取数据的内存缓冲区起始地址
    • size:单个数据块的字节大小
    • count:要读取的数据块总个数
    • stream:源文件指针
  • 返回值:实际成功读取的完整数据块个数
    • 正常读取:等于 count
    • 读到文件末尾 / 读取出错:返回小于 count 的数值
    • 剩余字节不足 1 个数据块时,返回已读取的完整块数
3. 典型用法
int arr[5];
// 读取5个int大小的数据,存入arr数组
fread(arr, sizeof(int), 5, pf);

四、示例:结构体批量读写

这是 fread/fwrite 最常用的场景,直接批量读写结构体数据。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

// 定义学生结构体
typedef struct Stu
{
    char name[20];
    int age;
    float score;
} Stu;

int main()
{
    // ========== 1. fwrite 写入二进制文件 ==========
    Stu arr[] = {
        {"张三", 20, 95.5f},
        {"李四", 19, 88.0f}
    };

    FILE* pf_w = fopen("student.dat", "wb"); // 二进制写模式 wb
    if (pf_w == NULL)
    {
        perror("fopen write");
        return 1;
    }

    size_t ret_w = fwrite(arr, sizeof(Stu), 2, pf_w);
    printf("成功写入 %zu 个结构体\n", ret_w);

    fclose(pf_w);
    pf_w = NULL;

    // ========== 2. fread 读取二进制文件 ==========
    Stu read_arr[2];
    FILE* pf_r = fopen("student.dat", "rb"); // 二进制读模式 rb
    if (pf_r == NULL)
    {
        perror("fopen read");
        return 1;
    }

    size_t ret_r = fread(read_arr, sizeof(Stu), 2, pf_r);
    printf("成功读取 %zu 个结构体\n\n", ret_r);

    // 打印读取结果
    for (size_t i = 0; i < ret_r; i++)
    {
        printf("姓名:%s,年龄:%d,成绩:%.1f\n",
               read_arr[i].name, read_arr[i].age, read_arr[i].score);
    }

    fclose(pf_r);
    pf_r = NULL;
    return 0;
}

2. 三组格式化函数对比

scanf / printf:针对标准输入输出的格式化的输入输出函数

fscanf / fprintf:针对所有输入输出流的格式化的输入输出函数

sscanf / sprintf:从一个字符串中提取格式化的数据,把格式化的数据转换成字符串

sprintf 详细用法

1. 功能

按照指定格式,将多个数据拼接成一个完整的字符串,存入目标字符数组,自动在末尾追加结束符 \0。 常用于数字转字符串、拼接多段文本、构造格式化字符串。

2. 函数原型
int sprintf(char *str, const char *format, ...);
  • 参数:
    • str:目标字符数组的首地址,用来存放生成的字符串
    • format:格式控制字符串,和 printf 规则完全一致
    • ...:可变参数,对应格式符的待写入数据
  • 返回值:
    • 成功:返回实际写入的字符个数(不包含末尾的 \0
    • 失败:返回负值
3. 典型用法
char buf[100];
// 拼接字符串、整数、浮点数
sprintf(buf, "姓名:%s 年龄:%d 成绩:%.1f", "张三", 20, 95.5);

三、sscanf 详细用法

1. 功能

从一个已有的字符串中,按照指定格式提取数据,存入对应的变量地址。 常用于解析结构化字符串、从一行文本中拆分出多个数据。

2. 函数原型
int sscanf(const char *str, const char *format, ...);
  • 参数:
    • str:源字符串的首地址,即待解析的字符串
    • format:格式控制字符串,和 scanf 规则完全一致
    • ...:可变参数,对应格式符的变量地址(必须传地址)
  • 返回值:
    • 成功:返回成功匹配并赋值的参数个数
    • 解析失败 / 字符串读完:返回 EOF
3. 典型用法
char str[] = "张三 20 95.5";
char name[20];
int age;
float score;
// 从字符串中提取3个数据
sscanf(str, "%s %d %f", name, &age, &score);

四、示例

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
    // ========== sprintf 演示 ==========
    char buf[100];
    int len = sprintf(buf, "学号:%d  姓名:%s  总分:%d\n", 1001, "李四", 580);
    printf("生成的字符串:%s", buf);
    printf("字符串长度:%d\n\n", len);

    // ========== sscanf 演示 ==========
    char data[] = "1002 王五 590";
    int id;
    char name[20];
    int total;
    int cnt = sscanf(data, "%d %s %d", &id, name, &total);
    printf("成功解析 %d 个数据\n", cnt);
    printf("学号:%d,姓名:%s,总分:%d\n", id, name, total);

    return 0;
}
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值