FILE * e istream: conectar os dois?
Pergunta
Suponha que eu "popen" um executável, eu recebo um FILE*
em troca. Além disso, suponha que eu gostaria de "connect" este arquivo para um objeto istream
para processamento mais fácil, há uma maneira de fazer isso?
Solução
Não há nenhuma maneira padrão, mas se você quer uma solução rápida você pode obter o descritor de arquivo com fileno () e, em seguida, usar Josuttis' fdstream . Pode haver esforços similares em torno mas eu usei isso no passado distante e ele funcionou bem. Se nada mais, deve ser um muito bom mapa para implementar o seu próprio.
Outras dicas
Você pode começar afastado derivando std :: basic_streambuf ou std :: streambuf classes.
Algo ao longo destas linhas:
#include <stdio.h>
#include <iostream>
#define BUFFER_SIZE 1024
class popen_streambuf : public std::streambuf {
public:
popen_streambuf() : fp(NULL) {
}
~popen_streambuf() {
close();
}
popen_streambuf *open(const char *command, const char *mode) {
fp = popen(command, mode);
if (fp == NULL)
return NULL;
buffer = new char_type[BUFFER_SIZE];
// It's good to check because exceptions can be disabled
if (buffer == NULL) {
close();
return NULL;
}
setg(buffer, buffer, buffer);
return this;
}
void close() {
if (fp != NULL) {
pclose(fp);
fp = NULL;
}
}
std::streamsize xsgetn(char_type *ptr, std::streamsize n) {
std::streamsize got = showmanyc();
if (n <= got) {
memcpy(ptr, gptr(), n * sizeof(char_type));
gbump(n);
return n;
}
memcpy(ptr, gptr(), got * sizeof(char_type));
gbump(got);
if (traits_type::eof() == underflow()) {
return got;
}
return (got + xsgetn(ptr + got, n - got));
}
int_type underflow() {
if (gptr() == 0) {
return traits_type::eof();
}
if (gptr() < egptr()) {
return traits_type::to_int_type(*gptr());
}
size_t len = fread(eback(), sizeof(char_type), BUFFER_SIZE, fp);
setg(eback(), eback(), eback() + (sizeof(char_type) * len));
if (0 == len) {
return traits_type::eof();
}
return traits_type::to_int_type(*gptr());
}
std::streamsize showmanyc() {
if (gptr() == 0) {
return 0;
}
if (gptr() < egptr()) {
return egptr() - gptr();
}
return 0;
}
private:
FILE *fp;
char_type *buffer;
};
int main(int argc, char *argv)
{
char c;
popen_streambuf sb;
std::istream is(&sb);
if (NULL == sb.open("ls -la", "r")) {
return 1;
}
while (is.read(&c, 1)) {
std::cout << c;
}
return 0;
}
Claro que há uma maneira, implementar seu próprio istream
que pode ser construído a partir de um FILE*
.
Se você está perguntando se existe uma maneira padrão para fazer isso, então não.