c语言fopen函数的用法

99ANYc3cd6
预计阅读时长 19 分钟
位置: 首页 C语言 正文

fopen 是 C 标准库 <stdio.h> 中的一个核心函数,它的全称是 "file open"(文件打开),顾名思义,它的主要作用是打开一个文件,并建立一个文件流(FILE stream)与该文件的关联,后续所有的文件读写操作(如 fscanf, fprintf, fread, fwrite 等)都将通过这个文件流来进行。


函数原型

我们来看一下 fopen 函数在头文件 <stdio.h> 中的声明:

FILE *fopen(const char *filename, const char *mode);

参数说明

  1. filename (文件名)

    • 这是一个字符串指针const char *),指向你想要打开的文件的名称。
    • 文件名可以是相对路径(如 "data.txt", "../logs/app.log")或绝对路径(如 "/home/user/documents/report.pdf", "C:\\Users\\Admin\\data.txt")。
    • 如果文件不存在,在大多数写入模式下,系统会尝试创建一个新文件。
  2. mode (打开模式)

    • 这也是一个字符串指针const char *),它指定了文件将以何种方式被打开。
    • modefopen 用法的关键,它决定了你是读取、写入、还是读写,以及是覆盖原有内容还是在文件末尾追加

返回值

  • 成功时:返回一个指向 FILE 结构体的指针,这个指针通常被称为“文件流指针”或“文件句柄”,后续所有文件操作函数都需要它。
  • 失败时:返回 NULL 指针,失败的原因可能包括:文件不存在、路径错误、没有文件访问权限、磁盘已满等。

打开模式 (mode) 详解

mode 参数是 fopen 的核心,以下是最常用的几种模式:

模式字符串 含义 如果文件已存在 如果文件不存在 备注
"r" 只读 打开成功,文件指针指向文件开头。 失败,返回 NULL 最基本的读文件模式。
"w" 只写 清空,文件指针指向文件开头。 创建新文件。 危险模式,会直接覆盖已有文件的全部内容。
"a" 追加 文件指针指向文件末尾 创建新文件。 新写入的内容会添加到文件末尾,不会覆盖原有内容。
"r+" 读写 打开成功,文件指针指向文件开头。 失败,返回 NULL 可读可写,但不会自动清空文件。
"w+" 读写 清空,文件指针指向文件开头。 创建新文件。 可读可写,但打开时会清空文件内容,与 "w" 一样危险。
"a+" 读写 文件指针指向文件末尾 创建新文件。 读操作可以从任何位置开始,但写操作只能在末尾追加。

模式组合说明

  • 文本模式与二进制模式
    • 默认情况下,fopen文本模式打开文件,在这种模式下,系统会进行一些转换,例如在 Windows 系统下,\n(换行符)会被转换成 \r\n(回车+换行)。
    • 如果你想以二进制模式打开文件(处理图片、可执行文件等),需要在模式字符串末尾加上 "b"
    • "rb" (二进制只读), "wb" (二进制只写), "ab" (二进制追加), "r+b" (二进制读写)。

完整用法示例

下面通过几个完整的例子来演示 fopen 的用法。

示例 1:基本读写 ("r+" 模式)

这个例子演示了如何打开一个文件,读取其内容,然后写入新内容。

#include <stdio.h>
#include <stdlib.h> // 用于 exit 函数
int main() {
    FILE *fp;
    char filename[] = "test.txt";
    char content[100];
    // 1. 以读写模式打开文件
    fp = fopen(filename, "r+");
    if (fp == NULL) {
        perror("打开文件失败"); // perror 会打印出具体的错误信息
        return 1; // 返回非零表示程序异常退出
    }
    printf("文件 %s 打开成功!\n", filename);
    // 2. 读取文件内容
    if (fgets(content, sizeof(content), fp) != NULL) {
        printf("文件内容: %s", content);
    }
    // 3. 将文件指针移动到开头,以便写入
    rewind(fp); // 或者使用 fseek(fp, 0, SEEK_SET);
    // 4. 写入新内容,会覆盖文件开头原有的内容
    fprintf(fp, "这是新写入的内容,\n");
    // 5. 关闭文件
    fclose(fp);
    printf("文件操作完成,已关闭,\n");
    return 0;
}

示例 2:安全写入 ("a" 模式)

这个例子演示了如何安全地向文件追加内容,而不会丢失原有数据。

#include <stdio.h>
#include <stdlib.h>
#include <time.h> // 用于获取当前时间
int main() {
    FILE *fp;
    char filename[] = "log.txt";
    // 以追加模式打开文件
    fp = fopen(filename, "a");
    if (fp == NULL) {
        perror("打开日志文件失败");
        return 1;
    }
    // 获取当前时间
    time_t now;
    time(&now);
    char *time_str = ctime(&now);
    // 追加日志信息
    fprintf(fp, "[%s] 程序运行了一次,\n", time_str);
    // 关闭文件
    fclose(fp);
    printf("日志已追加到 %s\n", filename);
    return 0;
}

示例 3:二进制文件读写 ("wb""rb" 模式)

这个例子演示了如何处理二进制数据,比如写入和读取一个结构体。

#include <stdio.h>
#include <stdlib.h>
// 定义一个结构体
typedef struct {
    int id;
    char name[20];
    float score;
} Student;
int main() {
    FILE *fp;
    Student s1 = {101, "张三", 95.5f};
    Student s2;
    // 1. 以二进制写入模式打开文件
    fp = fopen("student.dat", "wb");
    if (fp == NULL) {
        perror("创建学生数据文件失败");
        return 1;
    }
    // 2. 将结构体 s1 的二进制数据写入文件
    fwrite(&s1, sizeof(Student), 1, fp);
    printf("学生信息已写入 student.dat\n");
    fclose(fp);
    // 3. 以二进制读取模式打开文件
    fp = fopen("student.dat", "rb");
    if (fp == NULL) {
        perror("读取学生数据文件失败");
        return 1;
    }
    // 4. 从文件中读取一个结构体的数据到 s2
    fread(&s2, sizeof(Student), 1, fp);
    printf("从文件读取的学生信息:\n");
    printf("ID: %d, Name: %s, Score: %.2f\n", s2.id, s2.name, s2.score);
    // 5. 关闭文件
    fclose(fp);
    return 0;
}

最佳实践与注意事项

  1. 始终检查返回值

    • 这是最重要的一条规则。fopen 可能会因为各种原因失败,永远不要假设它会成功,打开文件后,必须立即检查返回的指针是否为 NULL,使用 if (fp == NULL)if (!fp) 进行判断。
  2. 处理错误

    • fopen 失败时,不要让程序继续执行文件操作,否则会导致段错误(Segmentation Fault),应该打印错误信息并优雅地退出。perror 函数非常有用,它会打印出你提供的字符串,并附上系统具体的错误原因(如 "No such file or directory")。
  3. 使用 fclose 关闭文件

    • 当你完成文件操作后,必须调用 fclose(fp) 来关闭文件
    • 为什么必须关闭?
      • 释放资源:文件句柄是系统宝贵的资源,用完不关闭会导致资源泄漏。
      • 刷新缓冲区fprintf, fputs 等函数的输出通常先被写入内存中的缓冲区,只有当缓冲区满或文件关闭时,才会真正写入磁盘。fclose 会强制将缓冲区中剩余的数据写入文件,确保数据完整性。
      • 确保数据安全:程序异常退出时,未关闭的文件可能会丢失数据。
  4. 选择正确的模式

    • 明确你的意图:是只读、只写、还是读写?是覆盖还是追加?选错模式可能导致数据丢失或程序逻辑错误。
    • 特别是 "w""w+" 模式,要非常小心,它们会清空文件。
  5. 使用 feofferror 检查文件状态

    • 在循环读取文件时,不能仅用 while (fread(...)) 来判断是否结束,因为它会在读取到文件末尾的最后一个有效数据块后返回一次 true,下一次才返回 false
    • 正确的做法是结合 feof (检查是否到达文件末尾) 和 ferror (检查是否发生读写错误)。
      while (1) {
      size_t result = fread(buffer, 1, sizeof(buffer), fp);
      if (result > 0) {
          // 成功读取了 result 字节的数据
          // ...
      } else {
          // 读取结束或出错
          if (feof(fp)) {
              printf("已到达文件末尾,\n");
              break;
          }
          if (ferror(fp)) {
              perror("读取文件时发生错误");
              break;
          }
      }
      }

fopen 是 C 语言文件操作的基石,记住它的核心三要素:文件名、打开模式、返回的文件指针,遵循“检查返回值、正确处理错误、用完必关闭”的原则,就能安全、高效地使用 fopen 进行文件操作。

-- 展开阅读全文 --
头像
织梦图集不显示图片是何原因?
« 上一篇 03-24
dede为何无法生成内页?
下一篇 » 03-24

相关文章

取消
微信二维码
支付宝二维码

目录[+]