#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 — это размер внутреннего буфера. Если вы ожидаете получить мало данных, вы можете уменьшить их; если вы ожидаете больших объемов данных, вы можете увеличить их. Я думаю, это не будет иметь большого значения.