C语言read()函数读取为空问题排查求助
问题:输入'o'后按Ctrl+D,getFileName中read()无法读取内容
我需要实现菜单输入功能:输入字符对应菜单操作,输入'o'后需输入文件名。但输入'o'后按Ctrl+D时,getFileName函数里的read()读不到任何内容,调整缓冲区大小也没用。
相关代码
#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #define BUFF_FILENAME 256 void readFile(int *fd, char *fileName) { // 假设此处实现文件读取逻辑 } int getFileName(char fileName[BUFF_FILENAME]){ int r = read(STDIN_FILENO, fileName, BUFF_FILENAME); printf("\nBytes read = %d\n", r); printf("and filename is %sx\n", fileName); if(r == 0){ fprintf(stdout, "No file name entered\n"); } else if(r < 0){ fprintf(stderr, "There was an error reading the file name\n"); } return r; } int main(){ char menuOpt; int readRes; char fileName[BUFF_FILENAME] = ""; int fd; //displayMenu(0); while((readRes = read(STDIN_FILENO, &menuOpt, 1)) > 0){ if(menuOpt == 'o'){ fprintf(stdout, "Enter the file name: "); if(getFileName(fileName) > 0){ readFile(&fd, fileName); } } // else if(menuOpt == 'd'){ // fprintf(stdout, "do something"); // } else { // fprintf(stderr, "Invalid input\n"); // } } printf("%d\n", readRes); return 0; }
运行现象
输入仅为o加Ctrl+D时,输出如下:
Current output mode: ASCII ENTER: "o" to enter a file name "d" to select display mode "x" to exit oEnter the file name: Bytes read = 0 and filename is x No file name entered
程序之后会停在main的循环等待输入,但我并没有在“Enter the file name:”后输入任何内容。
解决方案
问题根源
当你在终端输入o后立即按Ctrl+D,终端会将o发送给程序,同时触发**EOF(文件结束符)**标记。此时main中的read读取到o后,调用getFileName时,read(STDIN_FILENO, ...)会直接返回0——因为标准输入流已经处于EOF状态。之后回到main的循环,read会持续返回0,但由于循环条件是readRes > 0,本应终止循环,但终端的缓冲特性可能导致程序表现异常,出现“等待输入”的假象。
修复方案
方案1:在EOF时终止程序
修改main函数,当getFileName返回0(检测到EOF)时,主动跳出循环终止程序:
while((readRes = read(STDIN_FILENO, &menuOpt, 1)) > 0){ if(menuOpt == 'o'){ fprintf(stdout, "Enter the file name: "); int fileNameRes = getFileName(fileName); if(fileNameRes > 0){ readFile(&fd, fileName); } else if(fileNameRes == 0){ // 文件名输入触发EOF,终止循环 break; } } }
方案2:改用标准库行输入函数(推荐)
read是无缓冲的底层调用,不符合终端行缓冲的交互习惯。改用fgets、fgetc等标准库函数,能更优雅处理EOF和用户输入:
首先修改getFileName:
int getFileName(char fileName[BUFF_FILENAME]){ fflush(stdout); // 确保提示信息立即输出 if(fgets(fileName, BUFF_FILENAME, stdin) == NULL){ if(feof(stdin)){ fprintf(stdout, "\nNo file name entered\n"); return 0; } else { fprintf(stderr, "\nError reading file name\n"); return -1; } } // 移除fgets读取的换行符 size_t len = strlen(fileName); if(len > 0 && fileName[len-1] == '\n'){ fileName[len-1] = '\0'; } printf("\nBytes read = %zu\n", len); printf("and filename is %sx\n", fileName); return len; }
然后修改main函数,用fgetc替代read(fgetc能正确返回EOF标记):
int main(){ int menuOpt; // 用int存储,因为EOF是int类型值 char fileName[BUFF_FILENAME] = ""; int fd; //displayMenu(0); while((menuOpt = fgetc(stdin)) != EOF){ if(menuOpt == 'o'){ fprintf(stdout, "Enter the file name: "); if(getFileName(fileName) <= 0){ // 输入错误或EOF,终止程序 break; } else { readFile(&fd, fileName); } } // 其他菜单逻辑 } printf("%d\n", menuOpt); return 0; }
这样修改后,输入o后按Ctrl+D,程序会检测到EOF,提示信息后直接终止,不会出现无意义的等待。
内容的提问来源于stack exchange,提问作者skushu
相关产品推荐
相关产品推荐

