C语言文件操作
在C语言中,文件操作主要是通过标准库函数来实现的。
今天有时间就来学习下一些常用的文件操作函数:
C 语言提供了一个 FILE 数据结构,记录了操作一个文件所需要的信息。该结构定义在头文件stdio.h
,所有文件操作函数都要通过这个数据结构,获取文件信息。
struct _iobuf
{char *_ptr; // 指向缓冲区当前位置的指针int _cnt; // 缓冲区中剩余的字节数char *_base; // 指向缓冲区起始位置的指针int _flag; // 文件状态标志(如错误、文件结束等)int _file; // 文件描述符或句柄int _charbuf; // 用于单字符缓冲int _bufsiz; // 缓冲区大小char *_tmpfname; // 临时文件名指针(如果有)
};
typedef struct _iobuf FILE; // 将结构体重命名为 FILE 类型
什么是文件指针:
开始操作一个文件之前,就要定义一个指向该文件的 FILE 指针,相当于获取一块内存区域,用来保存文件信息。
定义方式:
FILE* fp;
fopen()函数用来打开文件。所有文件操作的第一步,都是使用
fopen()打开指定文件。这个函数的原型定义在头文件
stdio.h
FILE* fopen(char* filename, char* mode);
它接受两个参数。第一个参数是文件名(可以包含路径),第二个参数是模式字符串,指定对文件执行的操作,比如下面的例子中,r
表示以读取模式打开文件;
第一次运行如果没有这个文件,程序会提示错误。如下所示,所以要想以只读的形式打开这个文件那么这样文件要事先存在。我在桌面手动创建了这个文件。再次试验就可以成果打开。
第一次打开出错:
第二次打开正常:
打开文件之后我们试着用fread()来读取文件信息。
fread()
函数用于一次性从文件读取较大的数据块,主要用途是将文件内容读入一个数组,适合读取二进制数据。它的原型定义在头文件stdio.h
。
size_t fread(void* ptr, size_t size,size_t nmemb,FILE* fp);
它接受四个参数
ptr
:数组地址。size
:每个数组成员的大小,单位为字节。nmemb
:数组的成员数量。fp
:文件指针。
读取字节数可以用一个变量来接收,
// 从文件中读取数据
BytesRead = fread(buffer, sizeof(char), sizeof(buffer) - 1, fp);
printf("读到字节数BytesRead = %d\r\n",BytesRead);
读取数据时候有可能遇到文件为空的情况,这时候就需要检查是不是文件末尾。检查是否到文件末尾函数是feof
feof
是 C 标准库中的一个函数,用于检查文件是否已到达文件末尾(EOF,End of File)。它通常与文件读写函数(如 fread
、fgets
等)一起使用,以便在读取文件时检测到文件末尾。
feof
函数原型
int feof(FILE *stream);
参数解释
stream
:指向FILE
结构的文件指针。
返回值
- 如果文件指针已到达文件末尾,则返回非零值 (真)。
- 否则,返回零 (假)。
如果文本文件里面的内容是空的、那么读取到的数据字节数据应该是0。如图所示。
现在我试着网文件里写入一些信息。再尝试去读取信息
写入的信息是
This is a test txt.
Hello world!
end
编写读取数据到buffer的代码
BytesRead = fread(buffer, sizeof(char), sizeof(buffer) - 1, fp);printf("读到字节数BytesRead = %d\r\n",BytesRead);if (BytesRead == 0){if (feof(fp))//文件到达末尾返回非零的真值 {printf("空文件、到达文件末尾\n");}else if (ferror(fp)){perror("没读到数据、读取文件时出错");}fclose(fp);return -1;}buffer[BytesRead] = '\0';printf("文件内容: %s\n", buffer);
读取信息入下所示:
打开文件时正常: No error
读到字节数BytesRead = 36
文件内容:
This is a test txt.
Hello world!
end
--------------------------------
Process exited after 0.04219 seconds with return value 0
请按任意键继续. . .
fclose
是 C 标准库中的一个函数,用于关闭已经打开的文件。关闭文件可以释放与该文件相关的资源,并确保所有缓冲区中的数据被写入文件。
fclose
函数原型
int fclose(FILE *stream);
参数解释
stream
:指向FILE
结构的文件指针,该文件指针指向要关闭的文件。
返回值
- 如果成功关闭文件,返回0。
- 如果发生错误,返回 EOF(通常为 -1)
完整的代码如下:
#include <stdio.h>int main(void)
{FILE *fp; // 定义一个 FILE 类型的指针char buffer[256]; // 定义一个缓冲区用于存储读取的数据size_t BytesRead; // 定义读取到多少个字节// 打开一个文件用于读取fp = fopen("example.txt", "r");if (fp == NULL){perror("打开文件时出错");return -1;}else{printf("打开文件正常\r\n");}// 从文件中读取数据BytesRead = fread(buffer, sizeof(char), sizeof(buffer) - 1, fp);printf("读到字节数 BytesRead = %zu\r\n", BytesRead);if (BytesRead == 0){if (feof(fp)) // 文件到达末尾返回非零的真值{printf("空文件或到达文件末尾\r\n");}else if (ferror(fp)){perror("没读到数据,读取文件时出错");}fclose(fp);return -1;}// 为缓冲区添加字符串结束符buffer[BytesRead] = '\0';printf("文件内容:\r\n%s\r\n", buffer);// 关闭文件if (fclose(fp) == 0) // fclose 关闭成功返回0,关闭失败返回EOF{printf("成功关闭文件\r\n");}else{perror("关闭文件时出错");}return 0;
}
补充说明:EOF
C 语言的文件操作函数的设计是,如果遇到文件结尾,就返回一个特殊值。程序接收到这个特殊值,就知道已经到达文件结尾了。
头文件stdio.h
为这个特殊值定义了一个宏EOF
(end of file 的缩写),它的值一般是-1
。这是因为从文件读取的二进制值,不管作为无符号数字解释,还是作为 ASCII 码解释,都不可能是负值,所以可以很安全地返回-1
,不会跟文件本身的数据相冲突。
需要注意的是,不像字符串结尾真的存储了\0
这个值,EOF
并不存储在文件结尾,文件中并不存在这个值,完全是文件操作函数发现到达了文件结尾,而返回这个值。
fopen打开文件模式可能情况
以下是 fopen
函数的所有可能模式及其详细解释,包括注意事项:
模式 | 模式说明 | 文件指针位置 | 文件存在 | 文件不存在 | 读操作 | 写操作 | 注意事项 |
---|---|---|---|---|---|---|---|
r | 读模式 | 文件开始 | 读取文件 | 返回 NULL | 允许 | 不允许 | 文件必须存在,否则返回 NULL。 |
w | 写模式 | 文件开始 | 文件内容被清空 | 创建新文件 | 不允许 | 允许 | 打开时会清空文件内容。 |
a | 追加写模式 | 文件末尾 | 文件末尾追加 | 创建新文件 | 不允许 | 允许 | 写操作总是在文件末尾。 |
r+ | 读写模式 | 文件开始 | 读取和写入 | 返回 NULL | 允许 | 允许 | 文件必须存在,否则返回 NULL。 |
w+ | 读写模式 | 文件开始 | 文件内容被清空 | 创建新文件 | 允许 | 允许 | 打开时会清空文件内容。 |
a+ | 读写模式 | 文件末尾 | 读取和追加 | 创建新文件 | 允许 | 允许 | 写操作总是在文件末尾。 |
注意事项
-
r
模式:- 只读模式,如果文件不存在,返回
NULL
。因此在打开文件后,必须检查文件指针是否为NULL
。
- 只读模式,如果文件不存在,返回
-
w
模式:- 只写模式,打开文件时会清空文件内容。如果文件不存在,则创建新文件。这种模式不允许读取文件内容。
-
a
模式:- 追加写模式,文件指针总是指向文件末尾。即使使用
fseek
移动文件指针,写入操作仍会在文件末尾。如果文件不存在,则创建新文件。这种模式不允许读取文件内容。
- 追加写模式,文件指针总是指向文件末尾。即使使用
-
r+
模式:- 读写模式,文件指针指向文件开始,允许读取和写入。如果文件不存在,返回
NULL
。因此在打开文件后,必须检查文件指针是否为NULL
。
- 读写模式,文件指针指向文件开始,允许读取和写入。如果文件不存在,返回
-
w+
模式:- 读写模式,打开文件时会清空文件内容,文件指针指向文件开始。如果文件不存在,则创建新文件。这种模式允许读取和写入,但注意文件内容会被清空。
-
a+
模式:- 读写模式,文件指针指向文件末尾,允许读取和追加。如果文件不存在,则创建新文件。尽管可以读取文件内容,但写操作总是在文件末尾。
示例代码
以下是如何使用这些模式打开文件的示例代码:
#include <stdio.h>void open_file(const char *filename, const char *mode)
{FILE *fp = fopen(filename, mode);if (fp == NULL) {perror("打开文件失败");return;}printf("以模式 '%s' 成功打开文件\r\n", mode);// 关闭文件if (fclose(fp) == 0) // fclose 关闭成功返回0,关闭失败返回EOF{printf("成功关闭文件\r\n");}else{perror("关闭文件时出错");}
}int main(void)
{open_file("example_r.txt", "r");open_file("example_w.txt", "w");open_file("example_a.txt", "a");open_file("example_r+.txt", "r+");open_file("example_w+.txt", "w+");open_file("example_a+.txt", "a+");return 0;
}
上边代码运行后只会产生四个文件
有关文件操作的接口还有以下几个,如果大家感兴趣可以点个在看,我继续更新!
fwrite():写入文件
fseek():移动文件指针到指定位置
ftell():获取文件指针当前位置
fgetc():从文件中读取一个字符
fputc():写入一个字符到文件中
fscanf():从文件中读取格式化输入
fprintf():按格式写入到文件中