为何使用fread从stdin读取时无法终止?如何解决?
解决fread从stdin读取时循环无法终止的问题
当你从终端交互式输入时,fread会一直阻塞等待输入——因为终端没有天然的EOF标识,必须手动触发(如Ctrl+D)才会让fread返回0,这就是循环停不下来的核心原因。要实现无需手动触发EOF的正常终止,可以从以下两种场景入手解决:
1. 为交互式输入设置结束标记
约定一个特定字符串作为输入结束信号,每次读取后检查缓冲区内容,匹配到标记就终止循环。比如用"###END###"作为结束标记(可根据需求调整),修改后的代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define END_MARK "###END###" int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "argument err"); return -1; } FILE *out_file = fopen(argv[1], "w"); if (out_file == NULL) { fprintf(stderr, "failed to open file"); return -1; } char buffer[20]; size_t ret; while ((ret = fread(buffer, 1, sizeof(buffer), stdin)) > 0) { // 检查缓冲区是否包含结束标记 char *mark_ptr = strstr(buffer, END_MARK); if (mark_ptr != NULL) { // 写入结束标记之前的有效内容 size_t valid_len = mark_ptr - buffer; if (valid_len > 0) { fwrite(buffer, 1, valid_len, out_file); } break; } // 正常写入读取到的内容 if (fwrite(buffer, 1, ret, out_file) != ret) { if (ferror(out_file)) { perror("write err:"); } } } fclose(out_file); // 必须关闭文件,确保缓冲区数据刷入磁盘 return 0; }
使用时,输入完内容后输入###END###即可终止循环。
2. 支持文件重定向/管道输入
如果输入来源是文件而非终端,直接通过重定向或管道传递输入,stdin会在文件末尾自动触发EOF,fread返回0后循环正常终止。示例命令:
# 从input.txt读取输入,写入output.txt ./your_program output.txt < input.txt # 通过管道传递输入 cat input.txt | ./your_program output.txt
注意事项
- 原代码遗漏关闭输出文件的操作,可能导致数据滞留在缓冲区未写入磁盘,务必添加
fclose(out_file)。 - 结束标记要选择不会出现在正常输入中的字符串,避免误触发终止。
- 若处理二进制数据,不要用字符串匹配,可改用特定字节序列作为结束标记。
内容的提问来源于stack exchange,提问作者professional pro
相关产品推荐
相关产品推荐

