Rya*_*yan 29 c io stdin file stream
我正在编写一个实用程序,它接受文件名或从stdin读取.
我想知道检查stdin是否存在的最强大/最快的方式(数据是否通过管道传输到程序),如果是,则读取该数据.如果不存在,则处理将在文件名上进行给出.我已经尝试使用以下测试的大小,stdin但我相信,因为它是一个流而不是一个实际的文件,它不起作用,因为我怀疑它会,它总是打印-1.我知道我总是可以一次读取输入1个字符!= EOF但是我想要一个更通用的解决方案,所以如果stdin存在我最终会得到fd或FILE*所以程序的其余部分将无缝运行.我希望能够知道它的大小,等待前一个程序关闭流.
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);
}
Run Code Online (Sandbox Code Playgroud)
终奌站:
$ echo "hi!" | myprog
Size of stdin: -1
Run Code Online (Sandbox Code Playgroud)
Lat*_*SuD 23
你认为这是错的.
你想做什么:
如果stdin存在使用它,否则检查用户是否提供了文件名.
你应该做什么代替:
如果用户提供文件名,则使用文件名.否则使用标准输入.
您无法知道传入流的总长度,除非您全部读取并保持缓冲.你只是不能向后寻找管道.这是管道工作方式的限制.管道不适合所有任务,有时需要中间文件.
mct*_*ylr 16
首先,要求程序通过检查errno在失败时设置的错误来告诉您错误,例如在fseek或期间ftell.
其他人(tonio和LatinSuD)解释了处理stdin与检查文件名时的错误.即,首先检查argc(参数计数)以查看是否指定了任何命令行参数if (argc > 1),将其-视为特殊情况含义stdin.
如果没有指定参数,则假设输入来自(go)stdin,这是一个非文件流,并且fseek函数失败.
对于流,您不能使用面向磁盘文件的库函数(即fseek和ftell),您只需计算读取的字节数(包括尾随换行符),直到接收到EOF(文件结束) .
对于大文件的使用,您可以通过使用fgetschar数组来加快速度,以便更有效地读取(文本)文件中的字节.对于二进制文件,您需要fopen(const char* filename, "rb")使用fread而不是使用fgetc/fgets.
您还可以检查for feof(stdin)/ ferror(stdin)when何时使用字节计数方法来检测从流中读取时的任何错误.
以下示例应符合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;
}
Run Code Online (Sandbox Code Playgroud)
除非用户提供文件名,否则您只能从标准输入读取?
如果不是,则将特殊的“文件名”-视为“从标准输入读取”的意思。用户必须启动程序,就像cat file | myprogram -他想将数据通过管道传输到它一样,myprogam file如果他希望它从文件中读取。
int main(int argc,char *argv[] ) {
FILE *input;
if(argc != 2) {
usage();
return 1;
}
if(!strcmp(argv[1],"-")) {
input = stdin;
} else {
input = fopen(argv[1],"rb");
//check for errors
}
Run Code Online (Sandbox Code Playgroud)
如果你在 *nix 上,你可以检查 stdin 是否是一个先进先出:
struct stat st_info;
if(fstat(0,&st_info) != 0)
//error
}
if(S_ISFIFO(st_info.st_mode)) {
//stdin is a pipe
}
Run Code Online (Sandbox Code Playgroud)
虽然这不会处理用户做 myprogram <file
您还可以检查 stdin 是否为终端/控制台
if(isatty(0)) {
//stdin is a terminal
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
106252 次 |
| 最近记录: |