2009-02-12 14 views
31

¿Hay alguna manera de crear un búfer de memoria como un ARCHIVO *. En TiXml puede imprimir el xml a un ARCHIVO * pero no puedo hacer que se imprima en un búfer de memoria.¿Cómo escribir en un búfer de memoria con un ARCHIVO *?

+1

Véase también [Diferencia entre fmemopen y open_memstream] (https: // stackoverflow .com/q/29849749/608639). – jww

Respuesta

2

se puede utilizar el método de TiXMLPrinterCStr la que la documentación indica:

El TiXmlPrinter es útil cuando se necesidad de:

  1. de impresión en la memoria (especialmente en el modo no-STL)
  2. Formato de control (terminaciones de línea, etc.)
16

Supongo que la respuesta correcta es la de Kevin. Pero aquí hay un truco para hacerlo con FILE *. Tenga en cuenta que si el tamaño del búfer (aquí 100000) es demasiado pequeño, perderá datos, ya que se escribe cuando se vacía el búfer. Además, si el programa llama a fflush() pierde los datos.

#include <stdio.h> 
#include <stdlib.h> 

int main(int argc, char **argv) 
{ 
    FILE *f = fopen("/dev/null", "w"); 
    int i; 
    int written = 0; 
    char *buf = malloc(100000); 
    setbuffer(f, buf, 100000); 
    for (i = 0; i < 1000; i++) 
    { 
     written += fprintf(f, "Number %d\n", i); 
    } 
    for (i = 0; i < written; i++) { 
     printf("%c", buf[i]); 
    } 
} 
+0

hack genial: ¿alguna idea si es portátil? –

+0

Funciona solo si puede evitar que stdio limpie el búfer, y supongo que los detalles de eso no están estandarizados. –

+6

'setbuf()' y 'setvbuf()' (NO 'setbuffer()') son ISO-C, por lo que * debería * ser portable una vez que los use. Si el modo de bofeteo está completamente amortiguado, debería tratar de llenar el búfer por completo; en Windows, debe usar "NUL" en lugar de "/ dev/null"; también debe abrir el archivo en modo binario "wb" – Christoph

8

fmemopen puede crear un ARCHIVO desde el búfer, ¿tiene sentido para usted?

4

me escribió un ejemplo sencillo de cómo me gustaría crear un archivo en memoria:

#include <unistd.h> 
#include <stdio.h> 

int main(){ 
    int p[2]; pipe(p); FILE *f = fdopen(p[1], "w"); 

    if(!fork()){ 
    fprintf(f, "working"); 
    return 0; 
    } 

    fclose(f); close(p[1]); 
    char buff[100]; int len; 
    while((len=read(p[0], buff, 100))>0) 
    printf(" from child: '%*s'", len, buff); 
    puts(""); 
} 
54

Hay una manera de POSIX de utilizar la memoria como un descriptor FILE: fmemopen o open_memstream, dependiendo de la semántica que desea buscar: Difference between fmemopen and open_memstream

+8

¡Ni fmemopen, ni open_memstream están definidos en ningún estándar de C/C++! – MFH

+0

@MFH POSIX 200809 – tbert

+13

¡POSIX NO es un estándar C/C++! Es un estándar que depende en gran medida del estándar C, pero, no obstante, solo funciona en un subconjunto de SOs que son compatibles con/desarrollados en C/C++. Sin mencionar que POSIX entra en conflicto con ciertos aspectos de los estándares de C/C++ ... – MFH

0

C++ basic_streambuf herencia

En C++, se debe evitar FILE* si puedes.

Al utilizar solo C++ stdlib, es posible crear una única interfaz que utilice de forma transparente el archivo o la memoria IO.

Este utiliza técnicas mencionadas en: Setting the internal buffer used by a standard stream (pubsetbuf)

#include <cassert> 
#include <cstring> 
#include <fstream> 
#include <iostream> 
#include <ostream> 
#include <sstream> 

/* This can write either to files or memory. */ 
void write(std::ostream& os) { 
    os << "abc"; 
}  

template <typename char_type> 
struct ostreambuf : public std::basic_streambuf<char_type, std::char_traits<char_type> > { 
    ostreambuf(char_type* buffer, std::streamsize bufferLength) { 
     this->setp(buffer, buffer + bufferLength); 
    } 
}; 

int main() { 
    /* To memory, in our own externally supplied buffer. */ 
    { 
     char c[3]; 
     ostreambuf<char> buf(c, sizeof(c)); 
     std::ostream s(&buf); 
     write(s); 
     assert(memcmp(c, "abc", sizeof(c)) == 0); 
    } 

    /* To memory, but in a hidden buffer. */ 
    { 
     std::stringstream s; 
     write(s); 
     assert(s.str() == "abc"); 
    } 

    /* To file. */ 
    { 
     std::ofstream s("a.tmp"); 
     write(s); 
     s.close(); 
    } 

    /* I think this is implementation defined. 
    * pusetbuf calls basic_filebuf::setbuf(). */ 
    { 
     char c[3]; 
     std::ofstream s; 
     s.rdbuf()->pubsetbuf(c, sizeof c); 
     write(s); 
     s.close(); 
     //assert(memcmp(c, "abc", sizeof(c)) == 0); 
    } 
} 

Por desgracia, no parece posible intercambiar FILE* y fstream: Getting a FILE* from a std::fstream

Cuestiones relacionadas