Read from file or stdin

前端 未结 6 1186
北恋
北恋 2020-11-30 01:08

I am writing a utility which accepts either a filename, or reads from stdin.

I would like to know the most robust / fastest way of checking to see if stdin exists (d

6条回答
  •  南笙
    南笙 (楼主)
    2020-11-30 02:06

    First, ask the program to tell you what is wrong by checking the errno, which is set on failure, such as during fseek or ftell.

    Others (tonio & LatinSuD) have explained the mistake with handling stdin versus checking for a filename. Namely, first check argc (argument count) to see if there are any command line parameters specified if (argc > 1), treating - as a special case meaning stdin.

    If no parameters are specified, then assume input is (going) to come from stdin, which is a stream not file, and the fseek function fails on it.

    In the case of a stream, where you cannot use file-on-disk oriented library functions (i.e. fseek and ftell), you simply have to count the number of bytes read (including trailing newline characters) until receiving EOF (end-of-file).

    For usage with large files you could speed it up by using fgets to a char array for more efficient reading of the bytes in a (text) file. For a binary file you need to use fopen(const char* filename, "rb") and use fread instead of fgetc/fgets.

    You could also check the for feof(stdin) / ferror(stdin) when using the byte-counting method to detect any errors when reading from a stream.

    The sample below should be C99 compliant and portable.

    #include 
    #include 
    #include 
    #include 
    
    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;
    }
    

提交回复
热议问题