Как открыть процесс и прочитать результаты в ifstream из программы на C ?

#c #c 11 #process #fstream #ifstream

#c #c 11 #процесс #fstream #ifstream

Вопрос:

Я пишу программу на C 11, которая будет выполняться в среде Unix (переносимость не вызывает беспокойства). В настоящее время у меня есть Makefile, который вызывает два процесса: один, который записывает в файл, а второй, который считывает из этого файла.

target:
mkfifo myfile
other_program > myfile amp;
my_program myfile

По разным причинам я хочу вызвать все это из my_program. Это выглядит popen многообещающе, поскольку оно вызывает внешний процесс и предоставляет ФАЙЛ *, который я могу прочитать. Однако существующий код обработки файлов, который я уже написал, использует ifstream:

std::ifstream stream1(argv[1]);

Есть ли достойный способ подключить popen ФАЙЛ * к ifstream? Есть ли что-то еще, что я должен использовать вместо popen ?

Ответ №1:

Вы можете создать буфер потока, который считывает данные из FILE* . Очевидно, что вам может потребоваться изменить свой код для использования std::istream в случае, если вы используете std::ifstream его в других местах, кроме создания потока, но это должно быть прямое изменение. Вот простая демонстрация, показывающая, как создать соответствующий буфер потока и как его использовать:

 #include <cstdio>
#include <iostream>

struct FILEbuf
    : std::streambuf {
    FILEbuf(FILE* fp): fp_(fp) {}
    int underflow() {
        if (this->gptr() == this->egptr()) {
            int size = fread(this->buffer_, 1, int(s_size), this->fp_);
            if (0 < size) {
                this->setg(this->buffer_, this->buffer_, this->buffer_   size);
            }
        }
        return this->gptr() == this->egptr()
            ? traits_type::eof()
            : traits_type::to_int_type(*gptr());
     }
     FILE* fp_;
     enum { s_size = 1024 };
     char  buffer_[s_size];
};

int main()
{
    FILEbuf      sbuf(popen("ls -l", "r"));
    std::istream in(amp;sbuf);
    for (std::string line; std::getline(in, line); ) {
        std::cout << line << 'n';
    }
}
  

В прошлом меня отчитывали за использование popen() или system() потому, что эти вызовы считаются небезопасными: оба этих вызова порождают оболочку, которую можно использовать для изменения их поведения. Альтернативой является создание буфера потока с использованием файловых дескрипторов и использование pipe() , dup() (или одного из его братьев и сестер), close() , fork() , и execl() (или одного из его братьев и сестер) для непосредственного построения канала.

Комментарии:

1. Спасибо, это работает! Хотя я не собираюсь притворяться, что понимаю некоторые функции / члены, которые вы реализовали как часть структуры FILEbuf . Есть ли причина, по которой s_size равен 1024?

2. @Chris: 1024 — это размер внутреннего буфера. Если вы ожидаете получить мало данных, вы можете уменьшить их; если вы ожидаете больших объемов данных, вы можете увеличить их. Я думаю, это не будет иметь большого значения.