1. 打开和关闭文件

打开文件

在使用文件前必须成功打开相应的文件才能够进行后续的读写操作。C 语言标准库中提供了 fopen 函数用于打开文件。

使用 C 语言标准库对文件进行操作需要包含头文件 stdio.h

fopen 函数

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

说明:

  1. pathname 参数是需要打开文件的路径(相对路径或决定路径)。
  2. mode 参数用于控制文件的打开方式和操作权限。
  3. 返回值是 FILE 类型的指针,用于对文件进行I/O 操作,我经常成之为文件流指针(stream)。成功则返回结构体地址,失败返回 NULL
  4. fopen函数发生错误时会设置全变变量 errno 的值。可以通过 perror 函数打印该值对应的错误信息。

FILE 是结构体类型别名,大致定义如下:

typedef struct {
    // ... 结构体内的成员变量
} FILE;

在使用标准库函数对文件进行操作时,我们无需关心 FILE 结构体的成员变量有哪些。

mode 参数详解

模式
说明
"r" 或 "rt"
从文件头位置读文本文件。
"r+" 或 "rt+"
从文件头位置读/写文本文件。
"w" 或 "wt"
从文件头位置写文本文件,没有文件则创建文件,文件存在则清空内容。
"w+" 或 "wt+"
从文件头位置读/写文本文件,没有文件则创建文件,文件存在则清空内容。
"a" 或 "at"
从文件头位置末尾写文本文件,没有文件则创建文件,文件存在则内容不变,在后面追加新内容。
"a+" 或 "at+"
从文件头位置末尾读/写文本文件,没有文件则创建文件,文件存在则内容不变,在后面追加新内容。

上述 mode 参数的值都是文本文件模式对文件进行操作。文本文件的读写方式默认是 t(text),可以省略不写。当以二进制方式对文件进行操作时,mode 参数的值中需要添加字符 b(binary)。

如下表所示

文本模式
二进制模式
说明
"r" 或 "rt"
"rb"
从文件头位置读文件。
"r+" 或 "rt+"
"rb+"
从文件头位置读/写文件。
"w" 或 "wt"
"wb"
从文件头位置写文件。
"w+" 或 "wt+"
"wb+"
从文件头位置读/写文件。
"a" 或 "at"
"ab"
从文件头位置末尾写文件(追加)。
"a+" 或 "at+"
"ab+"
从文件头位置末尾读/写文件(追加)。

关闭文件

在文件使用完毕后必须进行关闭,否则可能浪费资源和数据丢失。使用标准库函数 fclose 可以关闭 使用 fopen 成功打开的文件。

fclose 函数

int fclose(FILE *stream);

说明:

  1. stream 参数是 fopen 成功打开文件后返回的文件结构体指针。
  2. 成功关闭则返回 0,失败返回 EOF(-1),同时设置错误号 errno

示例:

尝试以文本文件只写的方式打开一个文件 myfile.txt,如果文件不存在则创建该文件并打开。

// filename: fopen_for_write.c
#include <stdio.h>

int main(int argc, char * argv[]) {
    FILE * pfile = NULL;  // 用于保存已经打开的文件

    // 打开文件 myfile.txt
    pfile = fopen("myfile.txt", "w");
    if (NULL == pfile) {
        // 根据全局变量 errno 错误号打印错误原因
        perror("打开文件 myfile.txt");
        return -1;
    }
    // ... 写入文件的内容(略)

    // 关闭文件
    fclose(pfile);

    return 0;
}

编译和运行结果如下:

weimingze@mzstudio:~$ ls
fopen_for_write.c
weimingze@mzstudio:~$ gcc -o fopen_for_write fopen_for_write.c
weimingze@mzstudio:~$ ./fopen_for_write
weimingze@mzstudio:~$ ls
fopen_for_write  fopen_for_write.c  myfile.txt
weimingze@mzstudio:~$ ls -l myfile.txt
-rw-r--r-- 1 weimingze weimingze 0 12月  5 14:35 myfile.txt

从运行结果可知,开始文件夹内只有 fopen_for_write.c 编译后多了一个 fopen_for_write文件,程序运行后又创建了 myfile.txtmyfile.txt 文件的长度是 0 字节。

示例:

尝试以文本文件只读的方式打开文件 myfile.txt,如果失败则报错。

// filename: fopen_for_read.c
#include <stdio.h>

int main(int argc, char * argv[]) {
    FILE * pfile = NULL;  // 用于保存已经打开的文件

    // 以只读方式打开文件 myfile.txt
    pfile = fopen("myfile.txt", "r");   //<-- 注意此处是 "r"
    if (NULL == pfile) {
        // 根据全局变量 errno 错误号打印错误原因
        perror("打开文件 myfile.txt");
        return -1;
    }
    // ... 读取文件的内容(略)

    // 关闭文件
    fclose(pfile);

    return 0;
}

编译和运行结果如下:

weimingze@mzstudio:~$ ls
fopen_for_read.c  myfile.txt
weimingze@mzstudio:~$ gcc -o fopen_for_read fopen_for_read.c
weimingze@mzstudio:~$ ls
fopen_for_read  fopen_for_read.c  myfile.txt
weimingze@mzstudio:~$ ./fopen_for_read
weimingze@mzstudio:~$ rm myfile.txt # 删除文件 myfile.txt
weimingze@mzstudio:~$ ls
fopen_for_read  fopen_for_read.c
weimingze@mzstudio:~$ ./fopen_for_read
打开文件 myfile.txt: No such file or directory

从运行结果可见,开始时存在文件 myfile.txt,程序运行不会有任何提示。当删除文件 myfile.txt 后再运行程序,则程序提示:No such file or directory

实验:

写程序,使用循环创建 file1.txtfile2.txtfile3.txt、... file20.txt 等一共 20 个空的文件。