C语言:文件操作

以下是关于 C语言文件操作 的系统性讲解,涵盖最常用的文件操作函数和典型使用场景。我会从基础开始,逐步介绍常用函数、注意事项和实际代码示例。

1. C语言文件操作的基本概念

C语言中文件操作主要通过标准库 <stdio.h> 提供的函数完成。
文件被视为字节流(stream),可以按文本模式二进制模式打开。

两种主要的文件流类型:

  • 文本模式(text mode):fopen 默认方式,处理换行符(Windows: \r\n\n 转换)
  • 二进制模式(binary mode):加上 b,不做任何转换,常用于图像、音频、可执行文件等

2. 常用文件操作函数一览

函数功能返回值成功时常用模式参数示例
fopen打开文件FILE*(成功)/ NULL"r", "w", "a", "rb", "wb"
fclose关闭文件0(成功)/ EOF
fread从文件读数据(块方式)实际读取的元素个数
fwrite向文件写数据(块方式)实际写入的元素个数
fgetc / getc读一个字符字符值 / EOF
fputc / putc写一个字符写入的字符 / EOF
fgets读一行(包含换行符)成功返回缓冲区指针
fputs写字符串(不写结束符)非负数(成功)/ EOF
fprintf格式化输出到文件写入的字符数 / 负值
fscanf格式化输入从文件成功匹配个数 / EOF
feof检查是否到达文件末尾非0(到达末尾)
ferror检查文件错误状态非0(有错误)
ftell获取当前文件位置(字节偏移)当前偏移量 / -1L
fseek移动文件指针位置0(成功)/ 非0SEEK_SET, SEEK_CUR, SEEK_END
rewind将文件指针移到开头无返回值
remove删除文件0(成功)/ 非0
rename重命名文件0(成功)/ 非0

3. 文件打开模式(fopen 的第二个参数)

模式含义文件不存在时文件已存在时指针初始位置
"r"只读失败打开文件开头
"w"只写(新建/清空)创建清空后写入文件开头
"a"追加写入创建追加到末尾文件末尾
"r+"读写失败打开文件开头
"w+"读写(新建/清空)创建清空后可读写文件开头
"a+"读+追加创建可读,写追加到末尾文件末尾
b二进制模式(如 "rb", "wb"同上同上同上

注意
Windows 和 Unix/Linux 在文本模式下对换行符处理不同,建议读写二进制文件时始终使用带 b 的模式。

4. 基本使用流程示例

示例1:逐字符读写(文本文件)

#include <stdio.h>

int main() {
    FILE *in = fopen("input.txt", "r");
    FILE *out = fopen("output.txt", "w");

    if (in == NULL || out == NULL) {
        perror("文件打开失败");
        return 1;
    }

    int ch;
    while ((ch = fgetc(in)) != EOF) {
        fputc(ch, out);
    }

    fclose(in);
    fclose(out);
    printf("复制完成\n");
    return 0;
}

示例2:按行读取(常用场景)

#include <stdio.h>
#define MAX_LINE 1024

int main() {
    FILE *fp = fopen("config.txt", "r");
    if (!fp) {
        perror("打开失败");
        return 1;
    }

    char line[MAX_LINE];
    while (fgets(line, sizeof(line), fp) != NULL) {
        printf("读取: %s", line);  // fgets 保留换行符
    }

    fclose(fp);
    return 0;
}

示例3:二进制文件读写(结构体)

#include <stdio.h>

typedef struct {
    int id;
    char name[32];
    float score;
} Student;

int main() {
    Student s1 = {1, "Alice", 95.5};
    Student s2;

    // 写入
    FILE *fp = fopen("students.dat", "wb");
    if (!fp) {
        perror("打开失败");
        return 1;
    }
    fwrite(&s1, sizeof(Student), 1, fp);
    fclose(fp);

    // 读取
    fp = fopen("students.dat", "rb");
    fread(&s2, sizeof(Student), 1, fp);
    printf("ID: %d, Name: %s, Score: %.1f\n", s2.id, s2.name, s2.score);
    fclose(fp);

    return 0;
}

示例4:随机读写(使用 fseek)

#include <stdio.h>

int main() {
    FILE *fp = fopen("data.bin", "r+b");
    if (!fp) {
        perror("打开失败");
        return 1;
    }

    int num;
    // 读取第3个整数(假设每个int占4字节)
    fseek(fp, 2 * sizeof(int), SEEK_SET);
    fread(&num, sizeof(int), 1, fp);
    printf("第3个数: %d\n", num);

    // 移动到文件末尾追加
    fseek(fp, 0, SEEK_END);
    int new_val = 999;
    fwrite(&new_val, sizeof(int), 1, fp);

    fclose(fp);
    return 0;
}

5. 常见问题与注意事项

问题解决/注意点
忘记关闭文件总是用 fclose,尤其是在循环或多文件操作时
检查 fopen 返回值永远不要假设打开成功,必须判断是否为 NULL
使用 feof 判断循环结束错误做法while(!feof(fp)) 常导致多读一行;正确用 while(fgets(...)) 或检查 fread 返回值
文本 vs 二进制模式二进制文件一定要用 b 模式,否则 Windows 可能破坏数据
缓冲区刷新fflush(fp) 可强制把缓冲区内容写入文件(对 stdout 也有效)
文件权限问题程序运行目录是否有写权限?(尤其在某些系统目录下)
大文件处理fseekftell 在某些系统对 >2GB 文件可能有问题,可用 fseeko/ftello(POSIX)

6. 推荐的健壮写法模板(读文件)

FILE *fp = fopen(filename, "r");
if (!fp) {
    fprintf(stderr, "无法打开文件: %s\n", filename);
    return -1;
}

// 读取操作...

if (ferror(fp)) {
    fprintf(stderr, "文件操作发生错误\n");
}

if (fclose(fp) != 0) {
    perror("关闭文件失败");
}

总结:最常用的几种模式

场景推荐模式常用函数组合
读取配置文件/日志"r"fgets, fscanf
覆盖写入新文件"w"fprintf, fwrite
追加日志"a"fprintf
读写二进制数据(结构体)"rb", "wb"fread, fwrite
随机访问文件"r+b"fseek, fread, fwrite

如果你有具体的使用场景(例如:复制文件、处理 CSV、读写结构体、错误恢复等),可以告诉我,我可以给出更针对性的代码示例或注意事项。

文章已创建 4298

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部