从文件或标准输入读取 [英] Read from file or stdin

查看:153
本文介绍了从文件或标准输入读取的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写一个工具,它可以接受一个文件名,或者从标准输入读取。

我想知道检查,看看是否标准输入是否存在(数据被输送到节目)的最健壮/最快的方法,如果是这样读取数据的。如果它不存在,则处理将发生在文件名给出。我已经尝试使用下面的测试标准输入的大小,但我相信,因为它是一个流,而不是实际的文件,它不工作,我怀疑它会,它总是打印 1 。我知道我可以总是在同时一次读取输入1个字符!= EOF但我想一个更通用的解决方案,所以我可以与任何一个FD或FILE *最后,如果标准输入存在,因此该方案的其余部分将无缝地发挥作用。我也想能够知道它的大小,已经由previous程序关闭了流悬而未决。

 长getSizeOfInput(FILE *输入){
  长retvalue = 0;
  fseek的(输入,0L,SEEK_END);
  retvalue = FTELL(输入);
  fseek的(输入,0L,SEEK_SET);
  返回retvalue;
}INT主(INT ARGC,字符** argv的){
  的printf(标准输入的大小:%ld的\\ n,getSizeOfInput(标准输入));
  出口(0);
}

终端:

  $回声嗨! | MYPROG
标准输入的大小:-1


解决方案

首先,让程序告诉你什么是错的通过检查错误号,这是设置在失败,如在 fseek的 FTELL

其他(托尼奥&安培; LatinSuD)曾与标准输入处理与检查文件名解释的错误。也就是说,首先检查 ARGC (参数计数),以查看是否有指定的任何命令行参数如果(argc个→1),处理 - 作为一个特殊的情况下,这意味着标准输入

如果没有指定参数,则假定输入(去)来自标准输入,这是一个没有文件,并在 fseek的功能上的失败。

在流,在那里你可以不使用文件在磁盘上的导向库函数的情况下(即 fseek的 FTELL ),你只需要数字节读取(包括结尾的换行字符)的数量,直到接收 EOF (结束文件)。

有关处理大型文件的使用情况您可以通过使用与fgets 为char数组在(文本)文件字节更加有效地读取加快速度。对于一个二进制文件,你需要使用的fopen(为const char *文件名,RB),并使用 FREAD 而不是龟etc /与fgets

您还可以检查为的feof(标准输入) / FERROR(标准输入)使用字节计数时方法从流中读取数据时发现任何错误。

下面的示例应该是C99的兼容性和移植。

 的#include<&stdio.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;&errno.h中GT;
#包括LT&;&string.h中GT;长getSizeOfInput(FILE *输入){
   长retvalue = 0;
   INT℃;   如果(输入!=标准输入){
      如果(-1 == fseek的(输入,0L,SEEK_END)){
         fprintf中(标准错误,错误寻求结束:%S \\ n字符串错误(错误));
         出口(EXIT_FAILURE);
      }
      如果(-1 ==(retvalue = FTELL(输入))){
         fprintf中(标准错误,FTELL失败:%S \\ n字符串错误(错误));
         出口(EXIT_FAILURE);
      }
      如果(-1 == fseek的(输入,0L,SEEK_SET)){
         fprintf中(标准错误,错误寻求启动:%S \\ n字符串错误(错误));
         出口(EXIT_FAILURE);
      }
   }其他{
      / *标准输入,我们需要整个流中读取直到EOF * /
      而(EOF!=(C =龟etc(输入))){
         retvalue ++;
      }
   }   返回retvalue;
}INT主(INT ARGC,字符** argv的){
   FILE *输入;   如果(argc个大于1){
      如果(!的strcmp(的argv [1], - )){
         输入=标准输入;
      }其他{
         输入= FOPEN(的argv [1],R);
         如果(NULL ==输入){
            fprintf中(标准错误,无法打开%s的:%S \\ n,
                  ARGV [1],字符串错误(错误));
            出口(EXIT_FAILURE);
         }
      }
   }其他{
      输入=标准输入;
   }   的printf(大小的文件:%LD \\ N,getSizeOfInput(输入));   返回EXIT_SUCCESS;
}

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 (data is being piped to the program) and if so reading that data in. If it doesn't exist, the processing will take place on the filename given. I have tried using the following the test for size of stdin but I believe since it's a stream and not an actual file, it's not working as I suspected it would and it's always printing -1. I know I could always read the input 1 character at a time while != EOF but I would like a more generic solution so I could end up with either a fd or a FILE* if stdin exists so the rest of the program will function seamlessly. I would also like to be able to know its size, pending the stream has been closed by the previous program.

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);
}

Terminal:

$ echo "hi!" | myprog
Size of stdin: -1

解决方案

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

这篇关于从文件或标准输入读取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆