Linux系统编程 - 标准IO
一、标准IO的三个标准流指针
系统为每个程序自动打开三个FILE * 流指针:
| 流指针 | 文件描述符 | 缓存类型 | 用途 |
|---|---|---|---|
stdin |
0 | 行缓冲 | 标准输入(键盘) |
stdout |
1 | 行缓冲 | 标准输出(屏幕) |
stderr |
2 | 无缓冲 | 标准错误(屏幕) |
特点:
-
程序启动时自动创建
-
不需要
fopen(),也不能fclose() -
可直接用于标准IO函数
cpp
#include <stdio.h>
int main() {
// 使用标准流指针
fprintf(stdout, "输出到屏幕\n"); // 等同于 printf
fprintf(stderr, "错误信息\n"); // 立即输出,无缓冲
fgetc(stdin); // 从键盘读取
return 0;
}
二、标准IO缓存机制
1. 缓存类型对比
| 缓存类型 | 大小 | 刷新条件 | 适用对象 |
|---|---|---|---|
| 行缓冲 | 1024字节 | 1. 遇到\n 2. 缓冲区满 3. 程序结束 4. fflush() |
stdin、stdout(终端设备) |
| 全缓冲 | 4096字节 | 1. 缓冲区满 2. 程序结束 3. fflush() 4. fclose() |
普通文件(磁盘文件) |
| 无缓冲 | 0字节 | 立即输出 | stderr |
2. 缓存刷新示例
cpp
#include <stdio.h>
#include <unistd.h>
int main() {
// 行缓冲示例
printf("Hello"); // 不立即输出(无\n)
printf(" World"); // 不立即输出
sleep(2);
printf("\n"); // 遇到\n,刷新输出
// 全缓冲示例
FILE *fp = fopen("test.txt", "w");
for(int i = 0; i < 5000; i++) {
fputc('A', fp); // 缓冲区满4096字节时才会写入文件
}
fflush(fp); // 手动刷新缓冲区
// 无缓冲示例
fprintf(stderr, "立即输出的错误信息\n");
fclose(fp);
return 0;
}
3. 强制刷新缓存
cpp
#include <stdio.h>
int main() {
// 刷新标准输出缓存
printf("正在处理...");
fflush(stdout); // 立即输出,不等待\n
// 刷新文件缓存
FILE *fp = fopen("data.txt", "w");
fputs("重要数据", fp);
fflush(fp); // 立即写入文件,防止数据丢失
// 设置缓存模式
setvbuf(stdout, NULL, _IONBF, 0); // 设置为无缓冲
setvbuf(fp, NULL, _IOFBF, 4096); // 设置为全缓冲,大小4096
fclose(fp);
return 0;
}
三、标准IO文件定位
1. 文件定位函数
cpp
#include <stdio.h>
int main() {
FILE *fp = fopen("test.txt", "r+");
if(fp == NULL) {
perror("fopen");
return -1;
}
// 1. fseek - 移动文件指针
fseek(fp, 0, SEEK_SET); // 移动到文件开头
fseek(fp, 10, SEEK_CUR); // 从当前位置向后移动10字节
fseek(fp, -5, SEEK_END); // 从文件末尾向前移动5字节
// 2. ftell - 获取当前位置
long pos = ftell(fp);
printf("当前位置:%ld字节\n", pos);
// 3. rewind - 重置到文件开头
rewind(fp);
printf("重置后位置:%ld字节\n", ftell(fp));
// 示例:计算文件大小
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
printf("文件大小:%ld字节\n", size);
rewind(fp);
fclose(fp);
return 0;
}
2. SEEK_宏定义
#define SEEK_SET 0 // 从文件开头
#define SEEK_CUR 1 // 从当前位置
#define SEEK_END 2 // 从文件末尾
四、选择原则
何时使用标准IO?
-
处理普通文件,需要缓冲提高性能
-
需要格式化输入输出(printf/scanf)
-
需要行操作(fgets/fputs)
-
跨平台应用