我正在编写一个实用程序,它可以接受文件名,也可以从标准输入中读取。
我想知道最健壮/最快的方法来检查stdin是否存在(数据正在通过管道传输到程序),如果存在,则读取该数据。如果它不存在,处理将在给定的文件名上进行。我试过使用下面的测试stdin
的大小,但我相信由于它是一个流而不是一个实际的文件,它不会像我想象的那样工作,它总是打印-1
。我知道我总是可以在!= EOF的时候一次读取输入的1个字符,但是我想要一个更通用的解决方案,这样我就可以得到一个fd或一个文件*,如果存在stdin,那么程序的其余部分就可以无缝地运行。我也想知道它的大小,悬而未决的流已经被以前的程序关闭。
long getSizeOfInput(FILE *input){
long retvalue = 0;
fseek(input, 0L, SEEK_END);
retvalue = ftell(input);
fseek(input, 0L, SEEK_SET);
return retvalue;
}
int main(int argc, char **argv) {
printf("Size of stdin: %ld\n", getSizeOfInput(stdin));
exit(0);
}
终端:
$ echo "hi!" | myprog
Size of stdin: -1
发布于 2010-08-16 16:58:56
首先,让程序通过检查errno
来告诉您哪里出了问题,这是在失败时设置的,例如在fseek
或ftell
期间。
其他人(tonio和LatinSuD)解释了处理标准输入而不是检查文件名的错误。也就是说,首先检查argc
(参数计数),看看是否有任何指定为if (argc > 1)
的命令行参数,将-
视为表示stdin
的特殊情况。
如果没有指定参数,那么假设输入来自stdin
,这是一个流而不是文件,并且fseek
函数在它上面失败。
在流的情况下,您不能使用面向磁盘文件的库函数(即fseek
和ftell
),您只需计算在收到EOF (文件结束)之前读取的字节数(包括尾随换行符)。
对于大文件的使用,您可以通过使用字符数组的fgets
来加快速度,以便更有效地读取(文本)文件中的字节。对于二进制文件,您需要使用fopen(const char* filename, "rb")
,并使用fread
而不是fgetc/fgets
。
您还可以在使用字节计数方法时检查feof(stdin)
/ ferror(stdin)
,以检测从流读取时的任何错误。
下面的示例应该是C99兼容和可移植的。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
long getSizeOfInput(FILE *input){
long retvalue = 0;
int c;
if (input != stdin) {
if (-1 == fseek(input, 0L, SEEK_END)) {
fprintf(stderr, "Error seek end: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if (-1 == (retvalue = ftell(input))) {
fprintf(stderr, "ftell failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if (-1 == fseek(input, 0L, SEEK_SET)) {
fprintf(stderr, "Error seek start: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
} else {
/* for stdin, we need to read in the entire stream until EOF */
while (EOF != (c = fgetc(input))) {
retvalue++;
}
}
return retvalue;
}
int main(int argc, char **argv) {
FILE *input;
if (argc > 1) {
if(!strcmp(argv[1],"-")) {
input = stdin;
} else {
input = fopen(argv[1],"r");
if (NULL == input) {
fprintf(stderr, "Unable to open '%s': %s\n",
argv[1], strerror(errno));
exit(EXIT_FAILURE);
}
}
} else {
input = stdin;
}
printf("Size of file: %ld\n", getSizeOfInput(input));
return EXIT_SUCCESS;
}
发布于 2010-08-16 16:31:33
你想错了。
你要做的是:
如果stdin存在,请使用它,否则请检查用户是否提供了文件名。
你应该做的是:
如果用户提供了文件名,则使用该文件名。否则使用stdin。
您无法知道传入流的总长度,除非您将其全部读取并保持缓冲。你就是不能向后寻找管道。这是管道工作方式的限制。管道并不适用于所有任务,有时需要中间文件。
发布于 2010-08-16 16:22:44
例如,您可能想看看在cat
实用程序中是如何做到这一点的。
请参见代码here。如果没有文件名作为参数,或者是"-",则使用stdin
作为输入。即使没有数据被推送到stdin
,它也会存在(但是,您的read调用可能会一直等待下去)。
https://stackoverflow.com/questions/3495092
复制相似问题