如何从argv指定文件或stdin读取?彩票程序stdin传参问题
其实核心思路很直白——先看命令行有没有传文件名参数:如果有,就打开对应文件读;如果没有,直接用标准输入stdin就行。关键是把输入源抽象成一个通用的流,这样后面的读取逻辑不用区分是文件还是键盘输入。
给你举个C语言的实际例子,一看就懂:
#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { FILE *input_stream; // 检查有没有传入文件名参数 if (argc > 1) { input_stream = fopen(argv[1], "r"); if (input_stream == NULL) { perror("打开文件失败"); exit(EXIT_FAILURE); } } else { // 没指定文件,直接用stdin input_stream = stdin; } // 接下来不管输入源是什么,都用这个stream读取就行 char buffer[256]; while (fgets(buffer, sizeof(buffer), input_stream) != NULL) { // 这里写你的数据处理逻辑 printf("读到内容:%s", buffer); } // 注意:如果是自己打开的文件要关闭,stdin不用关 if (input_stream != stdin) { fclose(input_stream); } return EXIT_SUCCESS; }
这样不管用户是敲./program myfile.txt还是直接./program(然后手动输入内容),程序都能正常工作。
你的情况是原来靠命令行参数传文件名,现在想用./program < file.txt这种重定向方式,但不知道怎么给evaluate_tickets(file, ...)传参数是吧?分两种情况给你说:
情况1:evaluate_tickets接受FILE*类型参数
如果你的函数是用FILE*来接收输入源的(就像上面例子里的input_stream),那简直完美——当用重定向的时候,直接把stdin传给它就行!
修改下主函数的逻辑就行:
int main(int argc, char *argv[]) { FILE *input_file; if (argc > 1) { input_file = fopen(argv[1], "r"); if (!input_file) { perror("打开文件失败"); exit(EXIT_FAILURE); } } else { // 重定向的时候,stdin就是file.txt的内容,直接传 input_file = stdin; } // 直接把input_file传给你的函数 evaluate_tickets(input_file, lottery_numbers, winner, ...); // 非stdin的文件记得关闭 if (input_file != stdin) fclose(input_file); }
这样不管用户用命令行参数还是重定向,函数都能正常读取数据,因为stdin本身就是一个合法的FILE*对象,和你打开的文件指针没区别。
情况2:evaluate_tickets必须接收文件名(字符串)
如果你的函数设计成必须传文件名(比如它内部要自己打开文件),那重定向的方式本身没法让程序知道stdin对应的是哪个文件——因为重定向是Shell帮你做的,程序本身看不到文件名。
这时候有个常用的小技巧:约定用"-"作为stdin的占位符。比如修改你的函数:
#include <string.h> void evaluate_tickets(const char *filename, ...) { FILE *fp; if (strcmp(filename, "-") == 0) { // 用户传了"-",就用stdin读取 fp = stdin; } else { fp = fopen(filename, "r"); if (!fp) { /* 这里加错误处理 */ } } // 后面的读取逻辑就统一用fp就行 // ... }
然后用户就可以两种方式运行:
- 原来的方式:
./program arg1 arg2 - 重定向等价方式:
./program - < file.txt(或者直接敲./program -,然后手动输入内容)
或者你也可以直接用问题1的解决方案,让程序自动判断是用文件还是stdin,这样用户不用特意传"-",直接./program < file.txt就行——前提是你把主函数的输入源处理好,再把对应的FILE*传给函数(如果能改函数参数的话,这是最优解)。
内容的提问来源于stack exchange,提问作者cgalvezg

