cin.tellg 从管道接收输入时返回 -1

Posted

技术标签:

【中文标题】cin.tellg 从管道接收输入时返回 -1【英文标题】:cin.tellg returns -1 when receiving input from a pipe 【发布时间】:2018-12-30 21:17:49 【问题描述】:

我有一种情况需要将子进程的输出通过管道传输到ifstream

我正在尝试使用以下方法从文件描述符创建 ifstream:How to construct a c++ fstream from a POSIX file descriptor?

我也尝试使用从子标准错误到我自己的标准输入的管道,并使用 cin 作为我的流。

在这两种情况下,当我调用 tellg 时,我都会得到 -1。

这是我的代码,其中包含从子标准错误到父标准输入的管道:

#include <iostream>

#include <unistd.h>
#include <sys/wait.h>

using namespace std;

int
main()

    int mypipe[2];

    pipe(mypipe);

    dup2(mypipe[0], STDIN_FILENO);
    dup2(mypipe[1], STDERR_FILENO);

    __pid_t pid = fork();

    if(pid == 0)
    
        // this is a process that outputs stuff into std::err
        char* argv[] = "copy-feats", nullptr;

        int ret = execvp(argv[0], argv);

        exit(ret);
    

    int status;
    waitpid(pid, &status, WNOHANG);

    cin.clear(); // attempting to clear the error state. Not working.
    long size = cin.tellg();
    cout << size << endl;

正如我所说,tellg 的输出是 -1。

我想如果我尝试使用 getline(cin, some_string) 我实际上可以看到子程序的输出。

我尝试从管道创建流,但它仍然给我 -1。

这是我使用的代码:

#include <iostream>
#include <fstream>
#include <ext/stdio_filebuf.h>

#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>

#define READ_FD  0
#define WRITE_FD 1

using namespace std;

using FilebufType = __gnu_cxx::stdio_filebuf<std::ifstream::char_type>;

int
main()

    int mypipe[2];

    pipe(mypipe);

    __pid_t pid = fork();

    if(pid == 0)
    
        dup2(mypipe[WRITE_FD], STDERR_FILENO);
        char* argv[] = "copy-feats", nullptr;

        int ret = execvp(argv[0], argv);

        exit(ret);
    

    int status;
    waitpid(pid, &status, WNOHANG);

    FilebufType filebuf(mypipe[READ_FD], std::ios::in);
    istream is(&filebuf);

    is.clear();
    auto size = is.tellg();
    cout << size << endl;

提前致谢。

【问题讨论】:

当然你从tellg()得到-1。管道是不可搜索的,当涉及到管道时,没有“文件位置”之类的东西。只有实际的物理文件是物理的,并提供文件位置。只有std::ifstreams 在附加到真实文件时提供文件位置指示。 查看返回值的含义。 @SamVarshavchik 谢谢你回答了我的问题。我建议您将其发布为答案,以使未来的访问者更清楚。 【参考方案1】:

实际上tellg() 仅在输入流是真实文件时才返回实际​​文件位置。也就是说,当输入流是std::ifstream时,只有当底层文件是普通文件时。

管道和其他非普通文件没有文件位置的概念。

在您使用的 Linux 上,tellg() 通常是通过使用 lseek(2) 实现的(间接地,但在此不相关),lseek(2)'s documentation 明确指定如果文件描述符返回 ESPIPE 错误是一个管道。最终,错误返回将转换为 tellg() 返回 -1。

【讨论】:

以上是关于cin.tellg 从管道接收输入时返回 -1的主要内容,如果未能解决你的问题,请参考以下文章

在 Kiosk 模式下配置时,是不是可以从 HoloLens 2 中的门户接收虚拟输入

嵌套类型未从父级接收用户输入

接收器关闭并在尝试通过通道发送时返回 SendError

当使用多个规则时,规则应该返回一个字符串或布尔值,而不是接收到的“对象”

使用 JavaScript 插入元素时无法接收表单输入数据

Django 表单未接收输入