FILE * e IStream: Collegare i due?
Domanda
Supponiamo che io "popen" un eseguibile, ho un FILE*
in cambio. Inoltre, supponiamo che io vorrei "connect" questo file a un oggetto istream
per l'elaborazione più facile, c'è un modo per fare questo?
Soluzione
Non c'è modo standard, ma se si vuole una soluzione rapida è possibile ottenere il descrittore di file con fileno () e quindi utilizzare Josuttis' fdstream . Ci possono essere gli sforzi simili in tutto, ma ho usato questo in un lontano passato ed ha funzionato benissimo. Se non altro dovrebbe essere una buona mappa per attuare il proprio.
Altri suggerimenti
Si può ottenere via derivando classi std :: basic_streambuf o std :: streambuf.
Qualcosa in questo senso:
#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;
}
Certo c'è un modo, implementare il proprio istream
che può essere costruito da un FILE*
.
Se stai chiedendo se esiste un modo standard per fare questo, allora no.