使用指向stdin的文件指针进行fseek

14

根据命令行参数,我将文件指针设置为指向指定的文件或stdin(用于管道)。然后将此指针传递给许多不同的函数以从文件中读取。这是获取文件指针的函数:

FILE *getFile(int argc, char *argv[]) {
    FILE *myFile = NULL;
    if (argc == 2) {
        myFile = fopen(argv[1], "r");
        if (myFile == NULL)
           fprintf(stderr, "File \"%s\" not found\n", argv[1]);
    }
    else
        myFile = stdin;
    return myFile;
}

当指针指向标准输入(stdin)时,fseek似乎不起作用。我是这样说的,我使用它,然后使用fgetc,但我得到了意外的结果。这是否是预期行为,如果是,那么我该如何在流中移动到不同的位置?

例如:

int main(int argc, char *argv[]) {
    FILE *myFile = getFile(argc, argv); // assume pointer is set to stdin
    int x = fgetc(myFile); // expected result
    int y = fgetc(myFile); // expected result
    int z = fgetc(myFile); // expected result

    int foo = bar(myFile); // unexpected result

    return 0;
}

int bar(FILE *myFile) {
    fseek(myFile, 4, 0);
    return fgetc(myFile);
}

你的示例代码看起来很好(除非文件不存在,但这与你的问题无关)。 - J-16 SDiZ
听起来对我没问题。这是哪个编译器?您可以尝试在bar()函数内打印两个指针(stdin和myFile),以检查它们是否相同。 - leonbloy
@leonbloy:我发现问题实际上出在fseek()上。显然,当指针指向stdin时它不起作用?对此有什么想法吗?(更新了问题) - Tyler Treat
相关链接:https://dev59.com/HkzSa4cB1Zd3GeqPpMCs | https://dev59.com/1Zvga4cB1Zd3GeqP5KjN - Ciro Santilli OurBigBook.com
3个回答

18

是的,在stdin上使用fseek通常不起作用是很正常的,它通常只在磁盘文件或类似的东西上工作。

虽然这实际上是POSIX的事情,但你通常可以使用if (isatty(fileno(myFile)))来获得至少一个相当好的想法,以确定在特定文件中是否能够进行寻址。在某些情况下,isatty和/或fileno将具有前导下划线(例如,我记得Microsoft编译器提供的版本会这样)。


那么我猜我的问题是 - 这可能很愚蠢 - 我该如何在流中移动到不同的索引?我认为会有比在循环中调用 fgetc(myFile) n 次更优雅的解决方案吧? - Tyler Treat
6
@Tyler Treat:这是流和文件之间的根本区别。从概念上讲,来自流的输入不会存储在任何地方 - 流是短暂的,只有在使用时才生成。如果您需要在流中寻找数据,请将其读入内存并在那里进行搜索(或者,如果特别大,可以将其读入临时文件中)。 - caf
2
我在C11规范中没有找到关于“fseek在stdin上无法工作是完全正常的”的支持。您是否有C规范来支持当stdin是文本流时的情况? - chux - Reinstate Monica
3
将不正确的“fseek在stdin上无法工作”更改为“fseek在管道、套接字或FIFO上无法工作”。以下是一个示例,其中fseekstdin上完美地工作,因为stdin来自一个(可寻址)文件:./a.out <a.out - Ian D. Allen
@chux-ReinstateMonica: 我很想粗鲁地问一句:“你不明白‘正常’的哪一部分?” “正常”并不意味着“相反的情况永远不会发生”。但是,stdin作为一个交互式流不支持寻找是很正常的。我想,如果答案只包含第一句话,你可能还有一点争论的余地,但是考虑到第二段描述了一种确定寻找是否有效的方法,将答案解读为stdin上的寻找永远不起作用,或者任何类似的说法,完全没有意义。 - undefined
显示剩余2条评论

3

Fseek()基于lseek(),而lseek手册讨论了可能出现的错误,包括:

 [ESPIPE]           Fildes is associated with a pipe, socket, or FIFO.

如果标准输入(stdin)连接到一个伪终端(pseudo tty),那么它会具有套接字(socket)的行为。

2
ANSI C有关于此的规定吗? - Ciro Santilli OurBigBook.com

0
这是ANSI标准中关于fseek函数的相关条目:

对于文本流,偏移量应为零,或者偏移量应为与同一文件相关联的流上先前成功调用ftell函数返回的值,并且whence应为SEEK_SET。

因此,可能性存在,但有一些限制。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接