1. 标准IO:水管系统的「高效输水」
概念:在C库中定义的一组用于输入输出的函数,围绕流进行操作,流用FILE *来描述。
特点:
-
通过缓冲机制减少系统调用,提高效率,就像快递中转站批量处理包裹。
-
标准IO默认打开了三个流:stdin(标准输入)、stdout(标准输出)、stderr(标准错误)。
缓冲区:
-
全缓冲:与文件相关,缓冲区刷新条件包括程序正常退出、缓冲区溢出、强制刷新fflush、fclose关闭对应的流。
-
行缓冲:与终端相关,缓冲区刷新条件包括遇到\n、程序正常退出、缓冲区溢出、强制刷新fflush、fclose关闭对应的流。
-
不缓冲:没有缓冲区,标准错误。
计算缓冲区大小一般为1kb。
2. 函数接口:操作文件的「工具箱」
打开文件fopen:
FILE *fopen(const char *path, const char *mode)
功能:打开文件
参数:
-
path:打开的文件路径
-
mode:打开的方式,包括r、r+、w、w+、a、a+ 返回值:成功返回文件流,失败返回NULL
示例:
FILE *file = fopen("example.txt", "w");
// 检查文件是否成功打开
if (file == NULL) {
// 打印错误信息
perror("Failed to open file");
return 1;
}
// 文件操作...
// 关闭文件
fclose(file);
// 其他打开模式如 "r"、"a+" 等可根据需要修改,只需将 mode 参数改为对应的模式字符串
关闭文件fclose:
int fclose(FILE* stream);
功能:关闭文件 参数:stream:文件流
示例:
FILE *file = fopen("example.txt", "w");
// 检查文件是否成功打开
if (file == NULL) {
// 打印错误信息
perror("Failed to open file");
return 1;
}
// 文件操作...
// 关闭文件并检查是否成功
if (fclose(file) != 0) {
// 打印错误信息
perror("Failed to close file");
return 1;
}
读写操作:
- 按照字符串读写:
char * fgets(char *s, int size, FILE * stream);
int fputs(const char *s, FILE * stream);
fgets示例:
FILE *file = fopen("example.txt", "r");
// 检查文件是否成功打开
if (file == NULL) {
// 打印错误信息
perror("Failed to open file");
return 1;
}
// 定义缓冲区
char buffer[1024];
// 循环读取文件内容
while (fgets(buffer, sizeof(buffer), file) != NULL) {
// 打印读取的每一行
printf("Read line: %s", buffer);
}
// 关闭文件
fclose(file);
// 通过修改 mode 参数为 "w" 或 "a" 等,可以实现不同的写入操作,fputs 的使用方式与上述示例类似,只需将读取操作替换为写入操作即可
- 按照二进制的方式进行读写:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
fread示例:
FILE *file = fopen("example.bin", "rb");
// 检查文件是否成功打开
if (file == NULL) {
// 打印错误信息
perror("Failed to open file");
return 1;
}
// 定义存储数据的数组
int data[5];
// 从文件中读取数据
if (fread(data, sizeof(int), 5, file) != 5) {
// 打印错误信息
perror("Failed to read file");
}
// 关闭文件
fclose(file);
// fwrite 的使用方式与 fread 类似,只需将 fopen 的 mode 参数改为 "wb",并将 fread 替换为 fwrite 即可实现写入操作
通过fgets实现"wc -l 文件名"命令功能:计算文件行数。
#include <stdio.h>
int count_lines(const char *filename) {
// 打开文件
FILE *file = fopen(filename, "r");
// 检查文件是否成功打开
if (file == NULL) {
// 打印错误信息
perror("Failed to open file");
return -1;
}
// 定义行数计数器
int count = 0;
// 定义缓冲区
char buffer[1024];
// 循环读取文件内容
while (fgets(buffer, sizeof(buffer), file) != NULL) {
// 每读取一行,计数器加1
count++;
}
// 关闭文件
fclose(file);
// 返回行数
return count;
}
int main(int argc, char *argv[]) {
// 检查命令行参数是否正确
if (argc != 2) {
// 打印使用说明
printf("Usage: %s <filename>\n", argv[0]);
return 1;
}
// 调用函数计算行数
int lines = count_lines(argv[1]);
// 检查是否成功计算行数
if (lines == -1) {
return 1;
}
// 打印行数
printf("Number of lines: %d\n", lines);
return 0;
}
3. 文件定位操作:文件中的「导航系统」
void rewind(FILE *stream);
int fseek(FILE *stream, long offset, int whence);
long ftell(FILE *stream);
-
rewind:将文件位置指针定位到起始位置。
-
fseek:文件的定位操作,参数包括文件流、偏移量和相对位置。
-
ftell:获取当前的文件位置。
注:当打开文件的方式为a或a+时,fseek不起作用。
rewind示例:
FILE *file = fopen("example.txt", "r");
// 检查文件是否成功打开
if (file == NULL) {
// 打印错误信息
perror("Failed to open file");
return 1;
}
// 定义缓冲区
char buffer[1024];
// 循环读取文件内容
while (fgets(buffer, sizeof(buffer), file) != NULL) {
// 打印读取的每一行
printf("Read line: %s", buffer);
}
// 重置文件位置指针到起始位置
rewind(file);
// 再次循环读取文件内容
while (fgets(buffer, sizeof(buffer), file) != NULL) {
// 打印读取的每一行
printf("Read line again: %s", buffer);
}
// 关闭文件
fclose(file);
// fseek 和 ftell 的使用方式与上述示例类似,只需根据需要设置 offset 和 whence 参数即可实现不同的定位操作
避坑指南
-
缓冲区溢出可能导致数据丢失,注意合理设置缓冲区大小。
-
文件操作完成后务必关闭文件,避免资源泄漏。
-
使用fseek时,注意打开文件的方式是否兼容定位操作。