FILE * und istream: die beiden verbinden?
Frage
Angenommen, ich „popen“ eine ausführbare Datei, habe ich eine FILE*
im Gegenzug zu bekommen. Außerdem nehme ich würde diese Datei zu einem istream
Objekt für eine leichtere Verarbeitung zu „verbinden“ mögen, ist es eine Möglichkeit, dies zu tun?
Lösung
Es gibt keinen Standard-Weg, aber wenn Sie eine schnelle Lösung wollen, können Sie den Dateideskriptor mit fileno () und dann Josuttis verwenden fdstream . Es können ähnliche Bemühungen um, aber ich verwendet, um dieses in der fernen Vergangenheit und es funktionierte gut. Wenn nichts anderes sollte es eine sehr gute Karte sein, Ihre eigenen zu implementieren.
Andere Tipps
Sie können wegkommen std :: basic_streambuf oder std :: streambuf Klassen durch Ableiten.
Etwas in diese Richtung:
#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;
}
Sicher gibt es eine Möglichkeit, Ihre eigenen istream
implementieren, die von einem FILE*
aufgebaut werden kann.
Wenn Sie sich fragen, ob es eine standardisierte Möglichkeit, dies zu tun, dann nicht.