首先,请程序通过检查设置为失败的errno(例如在fseek 或ftell 期间)来告诉您出了什么问题。
其他人(tonio 和 LatinSuD)解释了处理标准输入与检查文件名的错误。即首先检查argc(参数计数),看是否有任何命令行参数指定if (argc > 1),将-视为特例含义stdin。
如果未指定参数,则假设输入(将要)来自stdin,这是一个流非文件,fseek 函数在其上失败。
在流的情况下,您不能使用面向磁盘文件的库函数(即fseek 和ftell),您只需计算读取的字节数(包括尾随换行符),直到接收 EOF(文件结尾)。
对于大文件的使用,您可以通过将 fgets 用于 char 数组来加快速度,以便更有效地读取(文本)文件中的字节。对于二进制文件,您需要使用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;
}