当前位置: 首页 > 面试题库 >

输入/输出管道

弓智明
2023-03-14
问题内容

本质上,我正在尝试替换:

/directory/program < input.txt > output.txt

为了避免使用硬盘驱动器,请在C ++中使用管道。这是我的代码:

//LET THE PLUMBING BEGIN 
int fd_p2c[2], fd_pFc[2], bytes_read;
    // "p2c" = pipe_to_child, "pFc" = pipe_from_child (see above link)
pid_t childpid;
char readbuffer[80];
string program_name;// <---- includes program name + full path
string gulp_command;// <---- includes my line-by-line stdin for program execution
string receive_output = "";

pipe(fd_p2c);//create pipe-to-child
pipe(fd_pFc);//create pipe-from-child
childpid = fork();//create fork

if (childpid < 0)
{
    cout << "Fork failed" << endl;
    exit(-1);
}
else if (childpid == 0)
{
    dup2(0,fd_p2c[0]);//close stdout & make read end of p2c into stdout
    close(fd_p2c[0]);//close read end of p2c
    close(fd_p2c[1]);//close write end of p2c
    dup2(1,fd_pFc[1]);//close stdin & make read end of pFc into stdin
    close(fd_pFc[1]);//close write end of pFc
    close(fd_pFc[0]);//close read end of pFc

    //Execute the required program
    execl(program_name.c_str(),program_name.c_str(),(char *) 0);
    exit(0);
}
else
{
    close(fd_p2c[0]);//close read end of p2c
    close(fd_pFc[1]);//close write end of pFc

    //"Loop" - send all data to child on write end of p2c
    write(fd_p2c[1], gulp_command.c_str(), (strlen(gulp_command.c_str())));
    close(fd_p2c[1]);//close write end of p2c

    //Loop - receive all data to child on read end of pFc
    while (1)
    {        
        bytes_read = read(fd_pFc[0], readbuffer, sizeof(readbuffer));

        if (bytes_read <= 0)//if nothing read from buffer...
            break;//...break loop

        receive_output += readbuffer;//append data to string
    }
    close(fd_pFc[0]);//close read end of pFc
}

我绝对可以确保上述字符串已正确初始化。但是,发生了两件事对我来说没有意义:

(1)我正在执行的程序报告“输入文件为空”。由于我未使用“ <”调用程序,因此不应期望输入文件。相反,它应该期待键盘输入。此外,它应该阅读“
gulp_command”中包含的文本。

(2)程序的报告(通过标准输出提供)出现在终端中。这很奇怪,因为此管道的目的是将stdout传输到我的字符串“
receive_output”。但是由于它出现在屏幕上,所以向我表明该信息没有通过管道正确传递给变量。如果我在if语句的末尾实现以下内容,

cout << receive_output << endl;

我什么也没得到,好像字符串是空的。我感谢您能给我任何帮助!

编辑:澄清

我的程序当前正在使用文本文件与另一个程序通信。我的程序编写了一个文本文件(例如input.txt),该文件由外部程序读取。然后,该程序将生成output.txt,我的程序会读取该文件。所以是这样的:

my code -> input.txt -> program -> output.txt -> my code

因此,我的代码当前使用的是

system("program < input.txt > output.txt");

我想使用管道替换此过程。我想将我的输入作为标准输入传递给程序,并让我的代码将该程序的标准输出读入字符串。


问题答案:

您的主要问题是您需要dup2()反转参数。您需要使用:

dup2(fd_p2c[0], 0);   // Duplicate read end of pipe to standard input
dup2(fd_pFc[1], 1);   // Duplicate write end of pipe to standard output

我陷入了误读您写为OK的错误的念头,直到我对设置代码进行错误检查并从dup2()调用中获得了意外的值,这告诉我出了什么问题。如果出现问题,请插入之前跳过的错误检查。

您也没有确保从子级读取的数据为空终止;此代码可以。

工作代码(带有诊断程序),使用cat最简单的“其他命令”:

#include <unistd.h>
#include <string>
#include <iostream>
using namespace std;

int main()
{
    int fd_p2c[2], fd_c2p[2], bytes_read;
    pid_t childpid;
    char readbuffer[80];
    string program_name = "/bin/cat";
    string gulp_command = "this is the command data sent to the child cat (kitten?)";
    string receive_output = "";

    if (pipe(fd_p2c) != 0 || pipe(fd_c2p) != 0)
    {
        cerr << "Failed to pipe\n";
        exit(1);
    }
    childpid = fork();

    if (childpid < 0)
    {
        cout << "Fork failed" << endl;
        exit(-1);
    }
    else if (childpid == 0)
    {
        if (dup2(fd_p2c[0], 0) != 0 ||
            close(fd_p2c[0]) != 0 ||
            close(fd_p2c[1]) != 0)
        {
            cerr << "Child: failed to set up standard input\n";
            exit(1);
        }
        if (dup2(fd_c2p[1], 1) != 1 ||
            close(fd_c2p[1]) != 0 ||
            close(fd_c2p[0]) != 0)
        {
            cerr << "Child: failed to set up standard output\n";
            exit(1);
        }

        execl(program_name.c_str(), program_name.c_str(), (char *) 0);
        cerr << "Failed to execute " << program_name << endl;
        exit(1);
    }
    else
    {
        close(fd_p2c[0]);
        close(fd_c2p[1]);

        cout << "Writing to child: <<" << gulp_command << ">>" << endl;
        int nbytes = gulp_command.length();
        if (write(fd_p2c[1], gulp_command.c_str(), nbytes) != nbytes)
        {
            cerr << "Parent: short write to child\n";
            exit(1);
        }
        close(fd_p2c[1]);

        while (1)
        {
            bytes_read = read(fd_c2p[0], readbuffer, sizeof(readbuffer)-1);

            if (bytes_read <= 0)
                break;

            readbuffer[bytes_read] = '\0';
            receive_output += readbuffer;
        }
        close(fd_c2p[0]);
        cout << "From child: <<" << receive_output << ">>" << endl;
    }
    return 0;
}

样本输出:

Writing to child: <<this is the command data sent to the child cat (kitten?)>>
From child: <<this is the command data sent to the child cat (kitten?)>>

请注意,您将需要小心以确保不会陷入代码僵局。如果您具有严格的同步协议(因此父级写一条消息并以锁步方式读取响应),则应该没问题,但如果父级正在尝试写一个太大而无法放入子级管道的消息当孩子试图写一条太大的消息而无法放入父级管道中时,则每个消息都将被阻止写入,而等待对方阅读。



 类似资料:
  • 问题内容: 我想在Linux操作系统上的C程序内执行以下操作: 使用syscall(或2)创建PIPE 使用exec()执行新流程 将流程的STDIN连接到先前创建的管道。 将流程的输出连接到另一个PIPE。 这样做的目的是为了性能目的而避免访问任何驱动器。 我知道使用PIPE系统调用创建管道非常简单,我可以使用popen为输入或输出目的创建管道。 但是您将如何针对输入和输出执行此操作? 问题答案

  • 问题内容: 有没有人有创建Java中的管道对象,任何好的建议 是 从Java既是一个InputStream和和OutputStream没有多重继承和两个流是抽象类,而不是接口? 基本需求是有一个可以传递给需要InputStream或OutputStream的对象的对象,该对象需要将一个线程的输出传递给另一个线程的输入。 问题答案: 看来这个问题的重点已被遗漏。如果我对您的理解正确,那么您希望一个对

  • 文件 std::fs::File 本身实现了 Read 和 Write trait,所以文件的输入输出非常简单,只要得到一个 File 类型实例就可以调用读写接口进行文件输入与输出操作了。而要得到 File 就得让操作系统打开(open)或新建(create)一个文件。还是拿例子来说明 use std::io; use std::io::prelude::*; use std::fs::File;

  • 回顾一下我们写的第一个 Rust 程序就是带副作用的,其副作用就是向标准输出(stdout),通常是终端或屏幕,输出了 Hello, World! 让屏幕上这几个字符的地方点亮起来。println! 宏是最常见的输出,用宏来做输出的还有 print!,两者都是向标准输出(stdout)输出,两者的区别也一眼就能看出。至于格式化输出,基础运算符和字符串格式化小节有详细说明,这里就不再啰嗦了。 更通用

  • Boost.Assign Assign帮助你把一系列的值赋给容器。它通过对operator, (逗号操作符) and operator()() (函数调用操作符)的重载,带给用户一种数据赋值的很容易的方法。除了对原型风格的代码特别有用,这个库的功能在其它时候也很有用,使用这个库有助于提高代码的可读性。使用本库中的list_of还可以就地生成无名数组。 Assign 的作者是 Thorsten Ot

  • 简介 通过前面章节的学习,你已经可以在Scheme的交互式前端中编写并执行程序了。在本章中,我讲介绍如何输入和输出。使用这个特性,你可以从文件中读取数据或向文件中写入数据。 从文件输入 open-input-file,read-char和eof-object? 函数(open-input-file filename)可以用于打开一个文件。此函数返回一个用于输入的端口。函数(read-char po