该文档主要讲解了 C 语言中标准 IO 库的相关操作,包括流的刷新、定位,格式化输入输出函数的使用,以及一个标准 IO 实战练习
一、流的刷新
1. fflush函数
- 函数原型:
int fflush(FILE *fp); - 功能:将流缓冲区中的数据写入实际文件。
- 返回值:成功返回 0,出错返回 EOF。
- 注意事项:
- 在 Linux 下只能刷新输出缓冲区,输入缓冲区会被丢弃。
- 若输出目标为屏幕,可使用
fflush(stdout)。
2. 代码示例
- 示例 1:刷新标准输出到屏幕
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
printf("abcdefg");
fflush(stdout); // 刷新标准输出缓冲区
while (1) {
sleep(1);
}
}
- 示例 2:刷新文件流
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
FILE *fp = fopen("1.txt", "w");
if (fp == NULL) {
perror("fopen");
return 0;
}
fwrite("abcdef", 7, 1, fp);
fflush(fp); // 刷新文件流缓冲区
while (1) {
sleep(1);
}
}
二、流的定位
1. 相关函数
-
ftell函数- 原型:
long ftell(FILE *stream); - 功能:获取流的当前读写位置。
- 返回值:成功返回位置偏移量,出错返回 EOF。
- 原型:
-
fseek函数- 原型:
long fseek(FILE *stream, long offset, int whence); - 功能:定位流的读写位置。
- 参数:
whence:定位基准,可选值为SEEK_SET(文件开头)、SEEK_CUR(当前位置)、SEEK_END(文件末尾)。offset:偏移量(可正可负)。
- 返回值:成功返回 0,出错返回 EOF。
- 原型:
-
rewind函数- 原型:
void rewind(FILE *stream); - 功能:将流的读写位置重置到文件开头。
- 等价于:
fseek(fp, 0, SEEK_SET);
- 原型:
2. 代码示例
#include <stdio.h>
int main(int argc, char *argv[]) {
FILE *fp = fopen("1.txt", "w");
if (fp == NULL) {
perror("fopen");
return 0;
}
fwrite("abcdef", 6, 1, fp);
printf("current fp=%d\n", (int)ftell(fp)); // 输出当前位置
rewind(fp); // 重置位置到开头
printf("After rewind fp=%d\n", (int)ftell(fp));
fwrite("vvv", 3, 1, fp);
}
3. 注意事项
- 文件以
a(追加)模式打开时,fseek无效。 - 三个函数仅适用于 2G 以下的文件。
三、格式化输出
1. fprintf函数
- 原型:
int fprintf(FILE *stream, const char *fmt, ...); - 功能:将数据格式化输出到文件流。
- 返回值:成功返回输出的字符数,出错返回 EOF。
2. sprintf函数
- 原型:
int sprintf(char *s, const char *fmt, ...); - 功能:将数据格式化输出到字符串。
- 返回值:成功返回输出的字符数,出错返回 EOF。
- 应用场景:字符串拼接(如日期格式化)。
3. 代码示例
- 示例 1:输出到字符串
#include <stdio.h>
int main() {
char buf[100] = {0};
int year = 2021, month = 10, day = 1;
sprintf(buf, "%d-%d-%d", year, month, day);
printf("%s\n", buf); // 输出:2021-10-1
}
- 示例 2:输出到文件
#include <stdio.h>
int main() {
FILE *fp = fopen("ftest.txt", "w");
if (fp == NULL) {
perror("fopen");
return 0;
}
int year = 2021, month = 10, day = 1;
fprintf(fp, "%d-%d-%d\n", year, month, day);
fclose(fp);
}
四、格式化输入
1. fscanf函数
- 原型:
int fscanf(FILE *stream, const char *format, ...); - 功能:从文件流中按格式读取数据。
- 返回值:成功返回读取的项数,出错返回 EOF。
2. sscanf函数
- 原型:
int sscanf(const char *str, const char *format, ...); - 功能:从字符串中按格式读取数据。
- 返回值:成功返回读取的项数,出错返回 EOF。
3. 代码示例
- 示例 1:从文件读取
#include <stdio.h>
int main() {
FILE *fp = fopen("ftest.txt", "r");
if (fp == NULL) {
perror("fopen");
return 0;
}
int year, month, day;
fscanf(fp, "%d-%d-%d", &year, &month, &day);
printf("%d,%d,%d\n", year, month, day);
fclose(fp);
}
- 示例 2:从字符串读取
#include <stdio.h>
int main() {
char buf[100] = {0};
int year = 2021, month = 10, day = 1;
sprintf(buf, "%d-%d-%d", year, month, day);
int syear, smonth, sday;
sscanf(buf, "%d-%d-%d", &syear, &smonth, &sday);
printf("%d,%d,%d\n", syear, smonth, sday);
}
五、标准 IO 练习:定时写入系统时间
1. 需求
- 每隔 1 秒向
test.txt文件追加当前系统时间,格式为序号, 年-月-日 时:分:秒。 - 程序无限循环,序号递增(基于文件已有行数)。
2. 关键函数
time():获取从 1970 年至今的秒数(time_t time(time_t *seconds))。localtime():将秒数转换为本地时间(struct tm *localtime(const time_t *timer))。struct tm结构体:包含年、月、日等时间字段(注意tm_mon需 + 1,tm_year需 + 1900)。
3. 代码实现
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main() {
FILE *fp = fopen("test.txt", "a+");
if (fp == NULL) {
perror("fopen");
return 0;
}
// 计算文件已有行数
int linecount = 0;
char buf[32] = {0};
while (fgets(buf, 32, fp) != NULL) {
if (buf[strlen(buf) - 1] == '\n') {
linecount++;
}
}
// 循环写入时间
while (1) {
time_t ctime = time(NULL);
struct tm *ctimestr = localtime(&ctime);
// 格式化输出时间
printf("%04d-%02d-%02d %02d:%02d:%02d\n",
ctimestr->tm_year + 1900, ctimestr->tm_mon + 1, ctimestr->tm_mday,
ctimestr->tm_hour, ctimestr->tm_min, ctimestr->tm_sec);
// 写入文件
fprintf(fp, "%d, %04d-%02d-%02d %02d:%02d:%02d\n",
linecount, ctimestr->tm_year + 1900, ctimestr->tm_mon + 1, ctimestr->tm_mday,
ctimestr->tm_hour, ctimestr->tm_min, ctimestr->tm_sec);
fflush(fp); // 刷新缓冲区到磁盘
linecount++;
sleep(1); // 间隔1秒
}
fclose(fp);
return 0;
}
4. 注意事项
- 行数计算:通过
fgets逐行读取并判断换行符\n。 - 缓冲区刷新:使用
fflush(fp)确保数据及时写入磁盘。 - 缓冲区大小:标准 IO 磁盘文件缓冲区一般为 4096 字节,标准输出为 1024 字节。
1069

被折叠的 条评论
为什么被折叠?



